Python多处理池线程是否安全?

时间:2016-10-31 22:41:27

标签: python django

我有Django项目。如果我创建包含 Pool()对象的包变量,并尝试从Django视图(以并行方式运行)使用该池,那么这样的线程安全吗?有没有其他方法可以做到这一点?

from multiprocessing import Pool
general_executor_pool = Pool()

2 个答案:

答案 0 :(得分:4)

我通过谷歌发现了这个问题,因为我问的是同一个问题。有趣的是,我可以说它不是,因为我最近调试了一个遭受竞争条件的软件。这是怎么回事:

  1. 主进程在一个循环中运行并在一个新线程中产生一个多处理池3分钟,其中包含〜1000个帐户的列表
  2. 该线程称为multiprocessing.Pool(max_proccesses = 32),pool.map(func,accounts)。这将打开32个流程,并逐个将每个帐户应用于可用流程。
  3. 原作者不知道,这个过程花费的时间要长于3分钟。那么下一次生成一个线程来创建多处理池时会发生什么?它是否产生了32个新进程,总共64个?不,在实践中它没有。相反,我的结果被扰乱,并显示出多个线程以非确定的方式对我的数据起作用。
  4. 我喜欢通过多处理模块进行跟踪,看看它是否是设计上的非线程安全的,或者是从知道的人那里得到答案。有趣的是,至少,我亲眼目睹了它不是。

答案 1 :(得分:0)

为了记录,我不得不检查这个,似乎 multiprocessing.pool.Pool 确实是线程安全的。 以下代码不会触发 AssertionError(使用 Python 3.6.9 测试):

import random
import time
import multiprocessing.pool
from threading import Thread

pool = multiprocessing.pool.Pool()

def return_value(value):
    time.sleep(random.random())
    return value
count = 100
def call_return_value():
    counter_start = random.randint(0, 100)
    result = list(range(counter_start, counter_start + count))
    pool_result = pool.imap_unordered(return_value, range(counter_start, counter_start + count), chunksize=1)
    pool_result = list(pool_result)
    assert set(pool_result) == set(result)
tl = [Thread(target=call_return_value) for _ in range(24)]
for t in tl:
    t.start()

基本上,这段代码启动了一个进程池,并启动了 24 个线程,通过这个池调用 return_value 函数。此函数在等待随机延迟(0 到 1 秒之间)后返回值。

当然,pool_result 不再排序,但它包含正确的元素集,这对所有线程都是正确的:值不会混合。