python - 为什么多处理的 apply_async 如此挑剔?

标签 python multithreading multiprocessing python-multithreading gil

没有问题的示例代码:

from multiprocessing import *
import time
import random

def myfunc(d):
    a = random.randint(0,1000)
    d[a] = a
    print("Process; %s" % a)

print("Starting mass threads")

man = Manager()
d = man.dict()
p = Pool(processes=8)

for i in range(0,100):
    p.apply_async(myfunc, [d])

p.close()
p.join()

print(d)

print("Ending multiprocessing")

如果将 p.apply_async(myfunc, [d]) 更改为 p.apply_async(myfunc, (d))p.apply_async(myfunc , d) 那么池将根本无法工作。如果您向 myfunc 添加另一个参数,然后传入 None ,它将像这样工作 p.apply_async(myfunc, (None, d)) — 但为什么呢?

最佳答案

apply_async 的文档说如下:

apply(func[, args[, kwds]])

Call func with arguments args and keyword arguments kwds. It blocks until the result is ready. Given this blocks, apply_async() is better suited for performing work in parallel. Additionally, func is only executed in one of the workers of the pool.

因此,它不采用星形和双星形参数,而是采用位置参数和关键字参数作为函数的第二个和第三个参数传递给目标函数;第二个必须是可迭代的,第三个必须是映射。


请注意,由于 apply 是异步工作的,因此您不会看到任何异常,除非您从结果中 .wait.get 它们;

您可以简单地尝试:

for i in range(0,100):
    result = p.apply_async(myfunc, d)

print(result.get())

在上面的代码中,result.get() 等待第 100 个线程完成并返回其返回值 - 或者尝试,因为它会失败,因为托管字典不能用作位置参数:

Traceback (most recent call last):
  File "test.py", line 21, in <module>
    print(result.get())
  File "/usr/lib/pythonN.N/multiprocessing/pool.py", line 558, in get
    raise self._value
KeyError: 0

因此,看看你原来的问题:请注意 [d] 是一个长度为 1 的列表; (d)d 相同;要获得长度为 1 的元组,您需要输入 (d,)。来自 Python 3 tutorial section 5.3 :

A special problem is the construction of tuples containing 0 or 1 items: the syntax has some extra quirks to accommodate these. Empty tuples are constructed by an empty pair of parentheses; a tuple with one item is constructed by following a value with a comma (it is not sufficient to enclose a single value in parentheses). Ugly, but effective. For example:

>>> empty = ()
>>> singleton = 'hello',    # <-- note trailing comma
>>> len(empty)
0
>>> len(singleton) 
1
>>> singleton 
('hello',)

(d,)[d]{d} 甚至 iter(frozenset(d)){d: True} 可以很好地用作位置参数;所有这些作为 args 都会产生一个 Iterable,其迭代器恰好产生 1 个值 - d 的值。另一方面,如果您传递了除了不幸的托管字典之外的几乎任何其他类型的值,您会得到一个更有用的错误;假设该值为 42,您将得到:

TypeError: myfunc() argument after * must be a sequence, not int

关于python - 为什么多处理的 apply_async 如此挑剔?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29585910/

相关文章:

python - Matplotlib 版本

python - 带有用 Python 编写的 FCGI 的 HTTP Web 服务器?

python - 当我调用 process.join 时,如何运行脚本?

multithreading - 在单例 session Bean 中管理并发访问

java - 使用 GeoTools 加载多线程几何图形

python - 管理具有不同内存使用情况的 Python 多进程进程

android - SharedPreferences 的 MODE_MULTI_PROCESS 不起作用

Python/Tracing - 如何从跟踪器中停止函数的执行(从中返回)

python - 为什么我的函数只能看到我的一些全局变量?

Java启动线程问题