python concurrent 模块

concurrent 介绍

concurrent.futures 是 Python 中的一个模块,提供了一个高级接口,用于异步执行函数或方法。
concurrent.futures 提供了2个池执行器:
  ThreadPoolExecutor:该类使用一组线程来异步执行调用。它适用于 I/O 密集型操作或不是 CPU 密集型的任务。
  ProcessPoolExecutor:这个类使用一组进程来异步执行调用。它适用于 CPU 密集型操作。
  
  # 需要放在主程序入口后执行:if __name__ == '__main__':

Future 对象

concurrent.futures.Future
done(): 如果调用被成功的取消或者执行完成,返回True
cancelled(): 如果调用被成功的取消,返回True
running(): 如果正在运行且不能被取消,返回True
cancel(): 尝试取消调用。如果已经执行且不能取消返回False,否则返回True
result(timeout=None): 取返回的结果,timeout为None,一直等待返回;timeout设置到期,抛出concurrent.futures.TimeoutError 异常
exception(timeout=None): 取返回的异常,timeout为None,一直等待返回;timeout设置到exception(timeout=None)期,抛出concurrent.futures.TimeoutError 异常
add_done_callback(fn): 用于向 Future 对象中添加回调函数。在并发编程中,当一个任务(对应 Future 对象)完成时,你可以通过 add_done_callback(fn) 方法注册一个回调函数,以便在任务完成后立即执行这个回调函数。
set_running_or_notify_cancel(): 如果该方法返回True,则Future未被取消,并已处于运行状态,即调用Future.running()将返回True。如果该方法返回False,则Future被取消,即Future.cancel()被调用并返回True。
set_result(result): 用于设置异步任务的结果。当一个异步任务完成并得到结果后,可以使用 set_result(result) 方法将结果设置到对应的 Future 对象中,使得其他地方可以获取到这个结果。
set_exception(exception):  用于设置异步任务的异常结果。当一个异步任务执行过程中出现异常时,可以使用 set_exception(exception) 方法将这个异常设置到对应的 Future 对象中,表示任务执行过程中发生了异常。

Executor 对象

concurrent.futures.Executor

submit()

submit(fn, /, *args, **kwargs):提交一个可调用的任务到线程池中以供执行。 等待 max_workers 里执行时间最长的任务,返回在最长时间内执行完成的所有结果。

    fn: 要执行的函数(可以是普通函数、lambda 函数或其他可调用对象)。
    *args: 传递给函数 fn 的位置参数。
    **kwargs: 传递给函数 fn 的关键字参数。
    
返回值:
    submit() 方法返回一个 Future 对象,代表异步执行操作的未来结果。通过这个对象,你可以等待任务完成,并获取任务执行的结果或异常,也可以取消任务的执行。
        #  <Future at 0x17e7d09aec0 state=running>
        #  <Future at 0x17e7d1f8dc0 state=pending>
        #  <Future at 0x17e7d09aec0 state=finished returned NoneType>

map()

map(fn, *iterables, timeout=None, chunksize=1):将函数应用于可迭代对象中的每个元素,并返回一个迭代器,包含了结果。

    fn: 要并行执行的可调用对象(比如函数)。
    *iterables: 一个或多个迭代器对象,包含输入到函数 fn 中的参数。
    timeout: 可选参数,指定等待所有任务完成的超时时间(以秒为单位)。
    chunksize: 可选参数,指定每次提交的任务数量。默认为 1,表示每次只提交一个任务。

返回值:
    map() 方法返回一个迭代器,迭代器会按照传入的参数迭代生成每个并行任务的结果。这样可以方便地批量处理数据,并行执行函数。

shutdown() 

shutdown(wait=True, *, cancel_futures=False):关闭线程池。

    wait: 这是一个布尔值,决定是否在关闭执行器之前等待所有任务完成。如果 wait=True,则会等待所有任务完成后才关闭线程池;如果 wait=False,则立即关闭线程池,不等待任务完成。
    cancel_futures: 这也是一个布尔值,决定是否取消尚未完成的任务。如果 cancel_futures 为 True 且 wait 为 False(即不等待任务完成就关闭执行器),那么所有未完成的任务都会被取消。如果 cancel_futures 为 False,则不会取消任何任务,即使执行器被关闭,这些任务仍会继续运行直到完成或抛出异常。默认值为 False。

模块功能

concurrent.futures.wait()

concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED): 用于等待一组并发任务完成。这个函数通常与线程池或进程池一起使用,允许你异步执行多个任务并等待它们完成。
    fs: 是一个可迭代的对象,包含了并发任务(通常是一个 Future 对象的列表或集合)。这些任务是之前通过线程池或进程池的 submit() 方法提交的。
    timeout: 是一个可选参数,指定等待任务完成的超时时间(以秒为单位)。如果在指定的时间内没有任务完成,函数将返回一个部分结果。如果设置为 None,则不会超时。
    return_when: 是一个可选参数,指定应该返回哪些任务的结果。它接受以下值之一:
        FIRST_COMPLETED: 当第一个任务完成时返回。
        FIRST_EXCEPTION: 当第一个任务引发异常时返回。
        ALL_COMPLETED: 当所有任务都完成时返回。这是默认值。
返回值:
    该函数返回一个包含两个集合的元组:(done, not_done)。其中 done 是已完成的任务集合,not_done 是未完成或仍在运行的任务集合。如果设置了超时并且部分任务未完成,这两个集合将包含部分完成的任务和未完成的任务。

concurrent.futures.as_completed()

concurrent.futures.as_completed(fs, timeout=None): 用于迭代一组 Future 对象,返回这些 Future 对象的结果,一旦它们完成就会生成结果。这个函数通常与线程池或进程池一起使用,允许你按照任务完成的顺序获取结果,而不需要等待所有任务都完成。
    fs: 是一个包含 Future 对象的可迭代对象,表示一组并发任务。
    timeout: 是一个可选参数,指定等待任务完成的超时时间(以秒为单位)。如果在指定的时间内没有任务完成,将会引发 concurrent.futures.TimeoutError 异常。如果不指定超时时间,那么函数将一直阻塞,直到所有任务完成才会返回结果。
        
返回值
    这个函数返回一个迭代器,可以遍历这个迭代器来获取 Future 对象的结果。当某个任务完成时,as_completed() 会生成相应的 Future 对象,你可以通过这个对象获取任务的结果。        
        

ThreadPoolExecutor

concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=()):
    max_workers(可选):如果max_workers为None或未给出,它将默认为计算机上的处理器数量乘以5,ThreadPoolExecutor通常用于I/O 密集型操作,并且worker的数量应该高于ProcessPoolExecuto的worker数量。
    thread_name_prefix(可选):为每个线程设置的名称前缀。默认是空的字符串。
    initializer(可选):一个可调用对象,用于在创建新线程时初始化每个线程的状态。通常用于设置线程的一些初始设置或状态。默认是 None。如果提供了此参数,它将在每个新线程启动时调用。此参数可以接受一个函数或可调用对象作为初始化器。
    initargs(可选):max_workers的默认值被设置为min(32, os.cpu_count() + 4)。这意味着它将根据系统的CPU核心数量来确定最大工作线程的数量,但不会超过一个特定的限制值.它最多使用32个CPU核来执行释放GIL的CPU受限任务。

ThreadPoolExecutor 主要特点

1. 异步执行任务:ThreadPoolExecutor 允许您将任务提交到线程池,线程池会异步执行这些任务。
2. 线程复用:线程池中的线程会被反复使用,而不是为每个任务创建一个新线程,这有助于减少线程创建和销毁的开销。
3. 任务管理:ThreadPoolExecutor 管理任务的执行,包括任务的提交、执行、完成和结果获取。
4. 上下文管理:ThreadPoolExecutor 支持使用 with 语句进行资源管理,当使用完毕时可以自动关闭线程池。

ThreadPoolExecutor 的基本步骤

1. 创建 ThreadPoolExecutor(max_workers=1) 实例:可以指定线程池的大小,通常根据机器的核心数来确定。
2. 提交任务给线程池:通过 executor.submit(func, *args, **kwargs) 方法提交任务,可以获得一个 Future 对象,表示该任务的未来结果。
3. 处理任务的结果:可以通过 Future 对象获取任务的执行结果,例如使用 future.result() 方法获取返回值。
4. 关闭线程池:使用 executor.shutdown(wait=True) 或者 with 语句来关闭线程池。

ThreadPoolExecutor 示例

submit()

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
import logging

FORMAT ='%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

def worker(n):
    logging.info(f'begin to worker {n}')
    time.sleep(n * 2)  # 模拟耗时任务
    logging.info(f'end to worker {n}')
    return n * n  # 返回结果


if __name__ == '__main__':
    executor = ThreadPoolExecutor(max_workers=2)

    with executor:

        futures = [executor.submit(worker, n) for n in [3, 1, 7, 5, 9]]

        for future in futures:
            logging.info(future.result())

    logging.info('=====end======')

输出结果

2024-07-17 11:20:29,096	 [MainProcess:ThreadPoolExecutor-0_0,38252:   27524]  begin to worker 3
2024-07-17 11:20:29,097	 [MainProcess:ThreadPoolExecutor-0_1,38252:   44536]  begin to worker 1
2024-07-17 11:20:31,105	 [MainProcess:ThreadPoolExecutor-0_1,38252:   44536]  end to worker 1
2024-07-17 11:20:31,105	 [MainProcess:ThreadPoolExecutor-0_1,38252:   44536]  begin to worker 7
2024-07-17 11:20:35,101	 [MainProcess:ThreadPoolExecutor-0_0,38252:   27524]  end to worker 3
2024-07-17 11:20:35,101	 [MainProcess:ThreadPoolExecutor-0_0,38252:   27524]  begin to worker 5
2024-07-17 11:20:35,101	 [MainProcess:MainThread,38252:    5264]  9
2024-07-17 11:20:35,101	 [MainProcess:MainThread,38252:    5264]  1
2024-07-17 11:20:45,115	 [MainProcess:ThreadPoolExecutor-0_0,38252:   27524]  end to worker 5
2024-07-17 11:20:45,115	 [MainProcess:ThreadPoolExecutor-0_1,38252:   44536]  end to worker 7
2024-07-17 11:20:45,115	 [MainProcess:ThreadPoolExecutor-0_0,38252:   27524]  begin to worker 9
2024-07-17 11:20:45,115	 [MainProcess:MainThread,38252:    5264]  49
2024-07-17 11:20:45,115	 [MainProcess:MainThread,38252:    5264]  25
2024-07-17 11:21:03,117	 [MainProcess:ThreadPoolExecutor-0_0,38252:   27524]  end to worker 9
2024-07-17 11:21:03,117	 [MainProcess:MainThread,38252:    5264]  81
2024-07-17 11:21:03,117	 [MainProcess:MainThread,38252:    5264]  =====end======

as_completed()

import concurrent.futures
import time
import logging

FORMAT ='%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

def worker(n):
    logging.info(f'begin to worker {n}')
    time.sleep(n * 2)  # 模拟耗时任务
    logging.info(f'end to worker {n}')
    return n * n  # 返回结果


if __name__ == '__main__':
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)

    with executor:

        futures = [executor.submit(worker, n) for n in [9, 1, 7, 5, 3]]

        for future in concurrent.futures.as_completed(futures):
            result = future.result()
            logging.info(future.result())

    logging.info('=====end======')

输出结果

2024-07-17 11:31:32,031	 [MainProcess:ThreadPoolExecutor-0_0,19328:   41752]  begin to worker 9
2024-07-17 11:31:32,031	 [MainProcess:ThreadPoolExecutor-0_1,19328:   16108]  begin to worker 1
2024-07-17 11:31:34,035	 [MainProcess:ThreadPoolExecutor-0_1,19328:   16108]  end to worker 1
2024-07-17 11:31:34,035	 [MainProcess:ThreadPoolExecutor-0_1,19328:   16108]  begin to worker 7
2024-07-17 11:31:34,035	 [MainProcess:MainThread,19328:   42652]  1
2024-07-17 11:31:48,047	 [MainProcess:ThreadPoolExecutor-0_1,19328:   16108]  end to worker 7
2024-07-17 11:31:48,047	 [MainProcess:ThreadPoolExecutor-0_1,19328:   16108]  begin to worker 5
2024-07-17 11:31:48,047	 [MainProcess:MainThread,19328:   42652]  49
2024-07-17 11:31:50,033	 [MainProcess:ThreadPoolExecutor-0_0,19328:   41752]  end to worker 9
2024-07-17 11:31:50,033	 [MainProcess:ThreadPoolExecutor-0_0,19328:   41752]  begin to worker 3
2024-07-17 11:31:50,033	 [MainProcess:MainThread,19328:   42652]  81
2024-07-17 11:31:56,044	 [MainProcess:ThreadPoolExecutor-0_0,19328:   41752]  end to worker 3
2024-07-17 11:31:56,044	 [MainProcess:MainThread,19328:   42652]  9
2024-07-17 11:31:58,050	 [MainProcess:ThreadPoolExecutor-0_1,19328:   16108]  end to worker 5
2024-07-17 11:31:58,050	 [MainProcess:MainThread,19328:   42652]  25
2024-07-17 11:31:58,050	 [MainProcess:MainThread,19328:   42652]  =====end======

map()

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
import logging

FORMAT ='%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

# 一个简单的任务,模拟耗时操作
# 一个简单的任务,计算平方
def square(n):
    logging.info(f'begin to worker {n}')
    time.sleep(5)
    logging.info(f'end to worker {n}')
    return n * n

# 创建 ThreadPoolExecutor 对象
with ThreadPoolExecutor(max_workers=3) as executor:
    # 定义一个列表
    numbers = [1, 2, 3, 4, 5]
    logging.info('====string====')

    # 使用 map 方法并行处理列表中的每个元素
    results = executor.map(square, numbers)

    logging.info('=' * 3)
    logging.info('*' * 3)

    # 输出结果
    for result in results:
        print(result)

    logging.info('====end====')

输出结果

2024-07-16 17:08:10,101	 [MainProcess:MainThread,12176:   46840]  ====string====
2024-07-16 17:08:10,102	 [MainProcess:ThreadPoolExecutor-0_0,12176:   36216]  begin to worker 1
2024-07-16 17:08:10,102	 [MainProcess:ThreadPoolExecutor-0_1,12176:   39836]  begin to worker 2
2024-07-16 17:08:10,102	 [MainProcess:ThreadPoolExecutor-0_2,12176:   10820]  begin to worker 3
2024-07-16 17:08:10,103	 [MainProcess:MainThread,12176:   46840]  ===
2024-07-16 17:08:10,103	 [MainProcess:MainThread,12176:   46840]  ***
1
4
2024-07-16 17:08:15,103	 [MainProcess:ThreadPoolExecutor-0_1,12176:   39836]  end to worker 2
2024-07-16 17:08:15,103	 [MainProcess:ThreadPoolExecutor-0_0,12176:   36216]  end to worker 1
2024-07-16 17:08:15,103	 [MainProcess:ThreadPoolExecutor-0_1,12176:   39836]  begin to worker 4
2024-07-16 17:08:15,103	 [MainProcess:ThreadPoolExecutor-0_0,12176:   36216]  begin to worker 5
2024-07-16 17:08:15,118	 [MainProcess:ThreadPoolExecutor-0_2,12176:   10820]  end to worker 3
9
2024-07-16 17:08:20,104	 [MainProcess:ThreadPoolExecutor-0_0,12176:   36216]  end to worker 5
2024-07-16 17:08:20,104	 [MainProcess:ThreadPoolExecutor-0_1,12176:   39836]  end to worker 4
2024-07-16 17:08:20,104	 [MainProcess:MainThread,12176:   46840]  ====end====
16
25

ProcessPoolExecutor

concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)
    max_workers(可选):如果max_workers为None或未给出,则默认为计算机上的处理器数量。如果max_workers小于或等于0,则将引发ValueError。在Windows上,max_workers必须小于或等于61。如果不是,则将引发ValueError。如果max_workers为None,则默认选择的最大值为61,即使有更多处理器可用。
    mp_context(可选): 用于设置进程的上下文环境。
    max_tasks_per_child(可选): 是一个可选参数,指定单个进程在退出并替换为新的工作进程之前可以执行的最大任务数。默认情况下,max_tasks_per_child为None,这意味着工作进程的寿命与池的寿命一样长。当指定最大值时,在没有mp_context参数的情况下,默认情况下将使用“spawn”多进程启动方法。此功能与“fork”启动方法不兼容。

submit()

import concurrent.futures
import time
import logging

FORMAT ='%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

def worker(n):
    logging.info(f'begin to worker {n}')
    time.sleep(n * 2)  # 模拟耗时任务
    logging.info(f'end to worker {n}')
    return n * n  # 返回结果


if __name__ == '__main__':
    executor = concurrent.futures.ProcessPoolExecutor(max_workers=2)

    with executor:

        futures = [executor.submit(worker, n) for n in [9, 1, 7, 5, 3]]

        for future in futures:
            logging.info(future.result())

    logging.info('=====end======')

输出内容

2024-07-17 11:37:04,123	 [SpawnProcess-1:MainThread,35364:   31948]  begin to worker 9
2024-07-17 11:37:04,128	 [SpawnProcess-2:MainThread,19760:   20056]  begin to worker 1
2024-07-17 11:37:06,141	 [SpawnProcess-2:MainThread,19760:   20056]  end to worker 1
2024-07-17 11:37:06,141	 [SpawnProcess-2:MainThread,19760:   20056]  begin to worker 7
2024-07-17 11:37:20,152	 [SpawnProcess-2:MainThread,19760:   20056]  end to worker 7
2024-07-17 11:37:20,153	 [SpawnProcess-2:MainThread,19760:   20056]  begin to worker 5
2024-07-17 11:37:22,133	 [SpawnProcess-1:MainThread,35364:   31948]  end to worker 9
2024-07-17 11:37:22,133	 [SpawnProcess-1:MainThread,35364:   31948]  begin to worker 3
2024-07-17 11:37:22,133	 [MainProcess:MainThread,44292:   31096]  81
2024-07-17 11:37:22,133	 [MainProcess:MainThread,44292:   31096]  1
2024-07-17 11:37:22,133	 [MainProcess:MainThread,44292:   31096]  49
2024-07-17 11:37:28,146	 [SpawnProcess-1:MainThread,35364:   31948]  end to worker 3
2024-07-17 11:37:30,157	 [SpawnProcess-2:MainThread,19760:   20056]  end to worker 5
2024-07-17 11:37:30,157	 [MainProcess:MainThread,44292:   31096]  25
2024-07-17 11:37:30,157	 [MainProcess:MainThread,44292:   31096]  9
2024-07-17 11:37:30,170	 [MainProcess:MainThread,44292:   31096]  =====end======

as_completed()

import concurrent.futures
import time
import logging

FORMAT ='%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

def worker(n):
    logging.info(f'begin to worker {n}')
    time.sleep(n * 2)  # 模拟耗时任务
    logging.info(f'end to worker {n}')
    return n * n  # 返回结果


if __name__ == '__main__':
    executor = concurrent.futures.ProcessPoolExecutor(max_workers=2)

    with executor:

        futures = [executor.submit(worker, n) for n in [9, 1, 7, 5, 3]]

        # for future in futures:
        #     logging.info(future.result())

        for future in concurrent.futures.as_completed(futures):
            result = future.result()
            logging.info(future.result())

    logging.info('=====end======')

输出结果

2024-07-17 11:39:21,794	 [SpawnProcess-1:MainThread,31948:   20056]  begin to worker 9
2024-07-17 11:39:21,802	 [SpawnProcess-2:MainThread,5436:   31096]  begin to worker 1
2024-07-17 11:39:23,813	 [SpawnProcess-2:MainThread,5436:   31096]  end to worker 1
2024-07-17 11:39:23,813	 [SpawnProcess-2:MainThread,5436:   31096]  begin to worker 7
2024-07-17 11:39:23,813	 [MainProcess:MainThread,44644:   15344]  1
2024-07-17 11:39:37,819	 [SpawnProcess-2:MainThread,5436:   31096]  end to worker 7
2024-07-17 11:39:37,819	 [SpawnProcess-2:MainThread,5436:   31096]  begin to worker 5
2024-07-17 11:39:37,819	 [MainProcess:MainThread,44644:   15344]  49
2024-07-17 11:39:39,806	 [SpawnProcess-1:MainThread,31948:   20056]  end to worker 9
2024-07-17 11:39:39,806	 [SpawnProcess-1:MainThread,31948:   20056]  begin to worker 3
2024-07-17 11:39:39,806	 [MainProcess:MainThread,44644:   15344]  81
2024-07-17 11:39:45,819	 [SpawnProcess-1:MainThread,31948:   20056]  end to worker 3
2024-07-17 11:39:45,819	 [MainProcess:MainThread,44644:   15344]  9
2024-07-17 11:39:47,831	 [SpawnProcess-2:MainThread,5436:   31096]  end to worker 5
2024-07-17 11:39:47,831	 [MainProcess:MainThread,44644:   15344]  25
2024-07-17 11:39:47,842	 [MainProcess:MainThread,44644:   15344]  =====end======

map()

from concurrent.futures import ProcessPoolExecutor
import time
import logging

FORMAT ='%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

# 一个简单的任务,模拟耗时操作
# 一个简单的任务,计算平方
def square(n):
    logging.info(f'begin to worker {n}')
    time.sleep(5)
    logging.info(f'end to worker {n}')
    return n * n

if __name__ == '__main__':
    # 创建 ProcessPoolExecutor 对象
    with ProcessPoolExecutor(max_workers=5) as executor:

        # 定义一个列表
        numbers = [1, 2, 3, 4, 5]
        logging.info('====string====')

        # 使用 map 方法并行处理列表中的每个元素
        results = executor.map(square, numbers)

        logging.info('=' * 3)
        logging.info('*' * 3)

        # 输出结果
        for result in results:
            print(result)

        logging.info('====end====')

输出结果

2024-07-16 17:46:21,841	 [MainProcess:MainThread,29156:    3084]  ====string====
2024-07-16 17:46:21,908	 [MainProcess:MainThread,29156:    3084]  ===
2024-07-16 17:46:21,908	 [MainProcess:MainThread,29156:    3084]  ***
2024-07-16 17:46:22,102	 [SpawnProcess-1:MainThread,2140:   42712]  begin to worker 1
2024-07-16 17:46:22,128	 [SpawnProcess-2:MainThread,46168:   31648]  begin to worker 2
2024-07-16 17:46:22,132	 [SpawnProcess-3:MainThread,34112:    2520]  begin to worker 3
2024-07-16 17:46:22,141	 [SpawnProcess-4:MainThread,40772:   28592]  begin to worker 4
2024-07-16 17:46:22,142	 [SpawnProcess-5:MainThread,14088:    6300]  begin to worker 5
2024-07-16 17:46:27,106	 [SpawnProcess-1:MainThread,2140:   42712]  end to worker 1
1
4
9
2024-07-16 17:46:27,137	 [SpawnProcess-2:MainThread,46168:   31648]  end to worker 2
2024-07-16 17:46:27,137	 [SpawnProcess-3:MainThread,34112:    2520]  end to worker 3
2024-07-16 17:46:27,153	 [SpawnProcess-4:MainThread,40772:   28592]  end to worker 4
2024-07-16 17:46:27,153	 [SpawnProcess-5:MainThread,14088:    6300]  end to worker 5
2024-07-16 17:46:27,154	 [MainProcess:MainThread,29156:    3084]  ====end====
16
25

示例

import concurrent.futures
import time
import logging

FORMAT = '%(asctime)-15s\t [%(processName)s:%(threadName)s,%(process)d:%(thread)8d]  %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)


def worker(n):
    logging.info(f'begin to worker {n}')
    time.sleep(n * 2)  # 模拟耗时任务
    logging.info(f'end to worker {n}')
    return n * n  # 返回结果


def ProcessPoolExecutor(max_workers, worker):
    executor = concurrent.futures.ProcessPoolExecutor(max_workers)

    with executor:
        futures = [executor.submit(worker, n) for n in [9, 1, 7, 5, 3]]

        for future in concurrent.futures.as_completed(futures):
            logging.info(future.result())

    logging.info('=====end======')


def ThreadPoolExecutor(max_workers, worker):
    numbers = [1, 2, 3, 4, 5]

    with concurrent.futures.ProcessPoolExecutor(max_workers) as executor:
        # 使用 map 方法并行处理列表中的每个元素
        futures = [executor.submit(worker, n) for n in [9, 1, 7, 5, 3]]

        logging.info('Results:')
        # 输出结果
        for future in concurrent.futures.as_completed(futures):
            logging.info(future.result())


if __name__ == '__main__':
    max_workers = 3
    ProcessPoolExecutor(max_workers, worker)
    ThreadPoolExecutor(max_workers, worker)

参考文档

https://docs.python.org/3/library/concurrent.futures.html

posted @ 2024-07-17 08:57  小吉猫  阅读(156)  评论(0编辑  收藏  举报