concurrent.futures模块之设置回调函数、取消任务以及异常处理

926 阅读2分钟

1.设置回调函数

concurrent.futures的回调函数是当前任务在等待执行之前被取消或执行完成后所触发的函数,回调函数必须设有参数fn,参数fn代表Future的实例对象,即任务提交执行后所生成的对象

from concurrent import futures
​
​
def task(n):
    return n / 10
​
​
def done(fn):
    if fn.cancelled:
        print(f'执行结果{fn.value}:取消')
    elif fn.done():
        error = fn.exception()
        if error:
            print(f'执行结果{fn.value}:错误返回{error}')
        else:
            result = fn.result()
            print(f'执行结果{fn.value}:正常返回{result}')
​
​
if __name__ == '__main__':
    thread = futures.ThreadPoolExecutor(max_workers=2)
    print('程序开始......')
    f = thread.submit(task, 5)
    f.value = 66
    f.add_done_callback(done)
    result = f.result()

result:

程序开始......
执行结果66:取消

2.取消任务

由于python设有GIL,多条线程在同时执行的时候,实质上只有一条线程在真正执行,其他的线程处于阻塞状态。当线程处于阻塞状态的时候,我们可以将线程取消执行

from concurrent import futures
import time
​
​
def task(n):
    time.sleep(3)
    return n / 10
​
​
def done(fn):
    if fn.cancelled:
        print(f'执行结果{fn.arg}:取消')
    elif fn.done():
        error = fn.exception()
        if error:
            print(f'执行结果{fn.arg}:错误返回{error}')
        else:
            result = fn.result()
            print(f'执行结果{fn.arg}:正常返回{result}')
​
​
if __name__ == '__main__':
    ex = futures.ThreadPoolExecutor(max_workers=1)
    print('程序开始......')
    tasks = []
    for i in range(3):
        print(f'开始执行任务:{i}')
        f = ex.submit(task, i + 1)
        f.arg = i + 1
        f.add_done_callback(done)
        tasks.append((i+1, f))
    for i, task_obj in tasks:
        if not task_obj.cancelled():
            print(f'不能取消{i}')

result:

程序开始......
开始执行任务:0
开始执行任务:1
开始执行任务:2
不能取消1
不能取消2
不能取消3
执行结果1:取消
执行结果2:取消
执行结果3:取消

3.处理异常

处理异常是任务在执行过程中出现异常而导致无法完整执行整个程序,如果使用result()获取执行结果,程序就会自动抛出线程或进程在执行过程中所出现的异常信息。此外,还可以使用exception()获取异常信息。

from concurrent import futures
​
​
def task():
    print('任务开始')
    raise ValueError("任务执行出错了")
​
​
if __name__ == '__main__':
    ex = futures.ThreadPoolExecutor(max_workers=2)
    print('程序开始......')
    f = ex.submit(task)
    error = f.exception()
    print(f'错误:{error}')
    try:
        result = f.result()
    except ValueError as e:
        print(f'访问异常{e}')

result:

程序开始......
任务开始
错误:任务执行出错了
访问异常任务执行出错了