您告诉 Python 执行函数 do_work(),然后将该函数返回的任何内容传递给 executor.do_work():
executor.submit(do_work(count))
如果您使用变量来保存do_work() 的结果,您可能会更容易看到这一点。以下在功能上等同于上述:
do_work_result = do_work(count)
executor.submit(do_work_result)
在 Python 中,函数是一等对象;仅使用名称 do_work 您正在引用函数对象。只有将(...) 添加到生成函数对象(或其他可调用对象类型)的表达式才会导致执行某些内容。
在表格中
executor.submit(do_work, count)
您确实不调用该函数。您将函数对象本身作为第一个参数传入,count 作为第二个参数传入。 executor.submit() 函数接受可调用对象及其参数,然后稍后使用提供的参数并行运行这些函数。
这允许ThreadPoolExecutor 获取该函数引用和单个参数,并且只在新线程中调用该函数,稍后。
因为您首先调用该函数,所以您必须等待每个函数首先完成,因为您在添加之前按顺序调用它。而且因为函数返回None,您将那些None 引用添加到executor.submit(),并且会看到TypeError 异常稍后告诉你'NoneType' object is not callable。发生这种情况是因为线程池执行程序尝试使用 None(),这不起作用,因为确实,None 不是可调用的。
在底层,库本质上是这样做的:
def submit(self, fn, *args, **kwargs):
# record the function to be called as a work item, with other information
w = _WorkItem(..., fn, args, kwargs)
self._work_queue.put(w)
所以引用函数和参数的工作项被添加到队列中。创建工作线程,再次从队列中获取项目(在另一个线程或子进程中),调用 _WorkItem.run() 方法,该方法运行您的函数:
result = self.fn(*self.args, **self.kwargs)
仅然后使用(...) 调用语法。因为有多个线程,所以代码是并发执行的。
您确实想了解纯 Python 代码如何不能并行运行,只能同时运行:Does Python support multithreading? Can it speed up execution time?
你的do_work() 函数只运行“更快”,因为time.sleep() 不需要做任何实际的工作,除了告诉内核不要给执行睡眠的线程任何执行时间,对于请求多少时间。你最终会得到一堆都睡着的线程。如果您的工作人员必须执行 Python 指令,那么并发或顺序运行这些函数所花费的总时间不会有太大差异。