使用ThreadPoolExecutor而不阻塞

时间:2017-11-14 15:41:35

标签: python multithreading threadpoolexecutor

作为对this question的跟进,我有一个简单的脚本,它会启动threadpoolexecutor来读取json文件。在这样做时,我想使用for循环从1到9计数。出于某种原因,即使我使用executor.shutdown(wait=False),它仍会阻塞并等待read_employees方法执行。

根据documentation

  

如果wait为False,则此方法将立即返回,并且当所有待处理的期货完成执行时,将释放与执行程序关联的资源

import concurrent.futures
import json
import time


def read_employees(read_file):
    with open(read_file) as f_obj:
        employees = json.load(f_obj)

    for emp in employees:
        print(emp)
        time.sleep(3)


def start_thread():
    filename = 'employee.json'
    with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
        executor.submit(read_employees, filename)
        executor.shutdown(wait=False)

def print_number():
    for num in range(1,10):
        time.sleep(2)
        print(num)


start_thread()
print_number()

如果我这样做:

def read_employees(read_file):
    with open(read_file) as f_obj:
        employees = json.load(f_obj)

    for emp in employees:
        time.sleep(5)
        print(emp)


def print_number():
    for num in range(1,10):
        print(num)


filename = 'employee.json'
empThread = threading.Thread(target=read_employees, args=(filename,))
empThread.start()

print_number()

首先计算从1到9,然后打印出员工,延迟是因为在阅读员工时睡觉。像这样:

1
2
3
4
5
6
7
8
9
ams@yourcompanyname.com
bcs@yourcompanyname.com

如何使用threadpoolexecutor无阻塞地实现相同的输出?

2 个答案:

答案 0 :(得分:3)

我建议您不要使用with声明。通过调用context managerwith方法关闭__exit__语句。上下文管理器是实现__enter____exit__方法的任何类。因此,在所有内容都在with语句中运行后,它会在传入的上下文管理器上调用__exit__

在这种情况下,ThreadPoolExecutor是一个上下文管理器。 ThreadPoolExecutorExecutor的子类。因此,通过引用Executor's class definition,我们会在其__exit__方法中看到它调用self.shutdown(wait=True)

调用self.shutdown(wait=True)是问题所在。如果您遵循上下文管理器的工作方式,由于self.shutdown(wait=False)with语句中的最后一项,__exit__将在之后直接调用。这意味着将调用self.shutdown(wait=True)。这就是什么阻碍了你。

您有两种方法可以解决此问题。第一个是子类ThreadPoolExecutor并重写__exit__方法。

第二种选择是做这样的事情:

def start_thread():
    filename = 'employee.json'
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
    executor.submit(read_employees, filename)
    executor.shutdown(wait=False)

答案 1 :(得分:0)

可能是由于这个小片段:

"如果使用with语句,则可以避免必须显式调用此方法,这将关闭Executor(等待Executor.shutdown()wait调用True 1}}设置为{{1}})"

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