ThreadPoolExecutor实现多线程并发并获得返回值(优雅简洁方式)

本文介绍了如何优雅简洁地使用ThreadPoolExecutor进行多线程并发查询,并通过Callable获取每个线程的返回值。示例代码展示了在Service层如何实现这一功能,适用于各种类型的数据查询场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言
数据库信息查询是大家最经常见到的工作问题。一般是单线程顺序查询,这样查询总时间是所有查询时间之和,消耗时间较长。如果采用多线程并行查询,则时间变成单个功能查询时间最长的。时间大大缩短。依据阿里开发规范,要重写ThreadPoolExecutor线程池,提高可控性。数据库查询还需要活动线程执行完的返回值,这样就不但要重写ThreadPoolExecutor,还得重写CallAble还获得返回值(RunAble不支持获得返回值)。下面给大家介绍一种优雅简洁实现上面功能的例子。
场景:实现多线程并发并获得返回值
代码:
因为大家contorller和dao层都很熟悉了,我这也不涉及他们的改变,就先省略。直接写需要改变的serviceImpl。
serviceImpl层:

package com.asiainfo.cem.uaa.service;

import com.asiainfo.cem.common.util.ParallelUtil;
import com.asiainfo.cem.common.util.ParallelUtil.ParallelJob;
import com.asiainfo.cem.uaa.common.UaaConstants;
import com.asiainfo.cem.uaa.domain.LoginUserDTO;
import com.asiainfo.cem.uaa.domain.SysUser;
import com.asiainfo.cem.uaa.dao.SysPermissionDao;
import com.asiainfo.cem.uaa.dao.SysRoleDao;
import com.asiainfo.cem.uaa.dao.SysUserDao;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 *@program: cem
 *@description:
 *@author: houzf
 */
@Service
public class UserServiceDetail implements UserDetailsService {

  @Autowired
  private SysUserDao sysUserDao;
  @Autowired
  private SysRoleDao sysRoleDao;
  @Autowired
  private SysPermissionDao sysPermissionDao;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    SysUser userDO = sysUserDao.findByUsername(username);
    if (userDO == null) {
      throw new UsernameNotFoundException(MessageFormat.format("{0} is empty.", username));
    }

    P
<think>嗯,用户问的是Python多线程并发获取每个线程的返回值。首先,我得回忆一下Python中多线程的基本用法。Python的threading模块是用来处理线程的,但线程在Python里因为GIL的存在,可能不太适合CPU密集型任务,不过对于I/O密集型任务还是有效的。用户的问题是如何获取每个线程的返回值,常规的threading.Thread类好像没有直接获取返回值的功能,因为run方法是不返回值的。这时候可能需要一些方法来收集线程的结果。 我记得可以用几种方法,比如通过子类化Thread类,重写run方法,把结果保存到一个实例变量里。或者使用共享的数据结构,比如队列,让线程把结果放到队列里,主线程再从队列中取出结果。还有一种方法是使用concurrent.futures模块里的ThreadPoolExecutor,这个可能更简单,因为它提供了Future对象,可以方便地获取返回值。 接下来,我需要考虑用户可能的实际情况。用户可能对多线程编程不太熟悉,所以需要给出明确的步骤和示例代码。比如,第一种方法,自定义线程类,添加一个result属性,然后在run方法里保存结果。主线程中可以调用线程对象的result属性来获取返回值。示例代码需要展示如何创建线程,启动,等待完成,然后收集结果。 第二种方法是用队列。每个线程把结果放入队列,主线程在join所有线程后,从队列中取出结果。这里需要注意的是队列是线程安全的,所以多个线程同时放数据不会有问题。示例代码需要导入queue模块,创建队列实例,线程函数接收队列作为参数,然后put结果进去。 第三种方法是使用concurrent.futures.ThreadPoolExecutor,这个模块更高级,用户可能更容易使用。通过submit方法提交任务,然后as_completed或者map来获取结果。这种方法代码更简洁,适合处理多个线程的返回值,而且可以处理异常。示例代码展示submit和as_completed的用法,或者使用map来简化。 还需要考虑线程间的同步问题,比如是否需要锁,但在这个问题中,因为每个线程独立生成结果,放到队列或自己的属性里,可能不需要锁。但如果用户的结果处理部分有共享资源,可能需要提醒,但根据问题描述,可能暂时不需要涉及。 另外,需要注意Python多线程的GIL问题,提醒用户多线程适合I/O密集型任务,而不是CPU密集型。这可能会影响用户的使用场景,所以需要提前说明。 最后,总结一下几种方法的优缺点。自定义线程类适合少量线程,代码简单。队列适合更复杂的线程间通信。而ThreadPoolExecutor适合需要管理线程池的情况,代码更简洁,功能更强大。用户可以根据具体情况选择合适的方法。 还需要检查示例代码的正确性,比如在自定义线程类中,是否正确地重写了构造函数和run方法,是否在start之后join,以确保结果已经生成。队列方法中,是否正确地处理了队列的获取,避免阻塞。ThreadPoolExecutor的示例是否正确使用上下文管理器,以及如何收集结果。 可能还需要提到错误处理,比如在线程中抛出异常的情况,但用户的问题主要是获取返回值,可能在基础示例中不需要涉及,但可以提及在高级使用中需要注意异常处理。 总结下来,应该分三个方法介绍,每个方法给出步骤、示例代码和说明,帮助用户理解如何获取多线程返回值。</think>在 Python 中实现多线程并发获取返回值,可通过以下三种典型方法实现: --- ### 方法 1:自定义线程类(继承 `threading.Thread`) ```python import threading class MyThread(threading.Thread): def __init__(self, target, args=()): super().__init__() self.target = target self.args = args self.result = None # 用于保存返回值的属性 def run(self): self.result = self.target(*self.args) # 执行目标函数保存结果 def worker(num): return f"线程{num}的返回值" # 创建启动线程 threads = [] for i in range(3): t = MyThread(target=worker, args=(i,)) t.start() threads.append(t) # 等待所有线程完成收集结果 results = [] for t in threads: t.join() results.append(t.result) print(results) # 输出: ['线程0的返回值', '线程1的返回值', '线程2的返回值'] ``` --- ### 方法 2:使用队列(`queue.Queue`) ```python import threading import queue def worker(q, num): q.put(f"线程{num}的返回值") # 将结果放入队列 q = queue.Queue() threads = [] for i in range(3): t = threading.Thread(target=worker, args=(q, i)) t.start() threads.append(t) # 等待所有线程完成 for t in threads: t.join() # 从队列中提取结果 results = [] while not q.empty(): results.append(q.get()) print(results) # 输出顺序可能不固定 ``` --- ### 方法 3:使用线程池(`concurrent.futures`) ```python from concurrent.futures import ThreadPoolExecutor, as_completed def worker(num): return f"线程{num}的返回值" with ThreadPoolExecutor(max_workers=3) as executor: # 提交任务获取 Future 对象 futures = [executor.submit(worker, i) for i in range(3)] # 按完成顺序获取结果 results = [] for future in as_completed(futures): results.append(future.result()) print(results) # 输出顺序不固定,如: ['线程1的返回值', '线程0的返回值', '线程2的返回值'] # 或按提交顺序获取结果 with ThreadPoolExecutor() as executor: results = list(executor.map(worker, range(3))) # 直接映射函数和参数 print(results) # 输出: ['线程0的返回值', '线程1的返回值', '线程2的返回值'] ``` --- ### 关键差异对比 | 方法 | 优点 | 缺点 | 适用场景 | |---------------------|-------------------------------|-------------------------------|------------------------| | 自定义线程类 | 完全控制线程逻辑 | 需手动管理线程生命周期 | 简单任务/少量线程 | | 队列 (`queue`) | 天然线程安全,结果顺序可控 | 需要额外队列管理 | 需要严格结果顺序时 | | 线程池 (`futures`) | 代码简洁,自动管理线程池 | 需要 Python 3.2+ | I/O 密集型并发任务 | --- ### 注意事项 1. **GIL 限制**:Python 多线程因全局解释器锁(GIL)**不适合 CPU 密集型任务**,建议用于 I/O 阻塞操作(如网络请求、文件读写)。 2. **结果顺序**:`as_completed` 按完成顺序返回结果,`executor.map` 保持参数顺序。 3. **异常处理**:使用 `future.exception()` 可捕获线程中抛出的异常。 根据实际需求选择最合适的方法即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MarquiS_houzf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值