前几天问了一次,很快沉了,再问问试试...
看 concurrent.futures 的文档,讲 ThreadPoolExecutor 的时候有一段
def wait_on_future():
f = executor.submit(pow, 5, 2)
# This will never complete because there is only one worker thread and
# it is executing this function.
print(f.result())
executor = ThreadPoolExecutor(max_workers=1)
executor.submit(wait_on_future)
看注释的意思应该是说如果 max_workers > 1 的话就不会有问题吧?可是为什么我把 max_workers 设为大于 1 的值, f 的状态还是一直卡在 pending 没输出结果呢? macOS 和 Linux 上都试过了。
1
IMRES 2016-07-26 10:20:19 +08:00
这个文档中的关于"deadlocks"的一个反面的例子……
需要将最后一行改为`wait_on_future()`才是正确的。 |
2
gnuth 2016-07-26 10:43:06 +08:00
https://github.com/python/cpython/blob/master/Lib/concurrent/futures/thread.py#L104-L114
wait_on_future 里面的 submit 卡在获取 _shutdown_lock 上了。 |
3
snachx OP @IMRES 我知道这里是讲 deadlocks ,但是根据注释,这个例子强调的是因为只有一个 worker ,所以会死锁,如果最后一行改为 wait_on_future(),即使 max_workers = 1 也不会有问题的啊
|
4
yangtukun1412 2016-07-26 10:55:09 +08:00
在 executor.submit(wait_on_future) 后面加上:
while True: time.sleep(1) 原因: 可以看下 concurrent/futures/thread.py 中的 _python_exit() 和 _worker() 两个函数. |
7
SuperFashi 2016-07-26 12:05:14 +08:00 via Android
所以真的是为什么……我设的 worker 为 2 顺利运行啊……
|
8
SuperFashi 2016-07-26 12:05:46 +08:00 via Android
楼上的都没有自己试一下吗?
|
9
snachx OP |
10
snachx OP @SuperFashi 是不管设为几都不行,而且注释的意思是设为 1 肯定不行,不理解了
|
11
ljbha007 2016-07-26 12:20:53 +08:00
除了线程的锁 python 还有一个全局锁 GIL 可能跟这有关系 但是我不没用过这个类 所以不清楚
|
12
SuperFashi 2016-07-26 12:28:12 +08:00 via Android
|
13
snachx OP @SuperFashi 我试了一下在 python shell 下面这么做确实没有问题,你试试写到文件里面,然后 python xxx.py 呢,你在 python shell 下面做跟前面说的睡一秒应该是一个意思吧
|
14
yangtukun1412 2016-07-26 13:15:13 +08:00 1
@snachx 大概说下吧
1. 设 executor.submit(wait_on_future) 启动的是线程 1, executor.submit(pow, 5, 2) 启动的是线程 2. 2. executor.submit(wait_on_future) 是非阻塞的, 所以在执行后主线程会退出. 3. 由于 thread.py 中注册了 _python_exit(), 所以会在主线程退出前执行这个函数, 1) 设置 _shutdown = True, 2) 向队列中 put 一个 None, 3) 阻塞在 t.join(sys.maxint) 这里等待全部子线程退出. 4. 线程 1 阻塞在 _worker() 中 work_item.run() 这一行, 因此 t.join(sys.maxint) 也会阻塞住, 阻止主线程退出. 5. 线程 2 从队列中 get 到的并不是 pow 函数对应的 work_item, 而是 _python_exit() 中 put 的 None, 再加上 shutdown == True, 所以线程 2 会不做任何操作直接退出. 6. 由于线程 2 已经退出, 所以 pow 函数没有被执行, 因此线程 1 也就永远被阻塞住了. 所以出现这个问题的原因就是主线程提前退出, 用 sleep 等方式阻止主线程退出就可以解决了, 你改成 executor.submit(wait_on_future).result() 也是一样 OK 的. |
15
SuperFashi 2016-07-26 13:17:44 +08:00 via Android
|
16
SuperFashi 2016-07-26 13:19:59 +08:00 via Android
啊 记错了 抱歉 用 result 阻塞就好了
|
17
snachx OP @yangtukun1412
之前已经知道了是主线程提前退出造成的,不过还没搞清楚具体流程。现在明白了,非常感谢~ |