Skip to main content
 首页 » 编程设计

python之如何使用多线程在 python 中共享一个变量(不是为了修改)

2024年10月17日34zdz8207

我正在尝试并行化我为顺序程序编写的函数。下面是输入输出

输入 1,字符串列表:["foo bar los angles", "foo bar new york", ...]

输入 2,作为字典的字符串列表:["los angles", "new york"..]

我想从输入 1 中删除输入 2 中的所有字符串。因此输出将如下所示:

["foo bar", "foo bar"]. 

我可以使用双 for 循环来完成。

res = [] 
for s1 in input1: 
    for s2 in input2: 
        if s2 in s1: 
            res.append(s1.replace(s2, "")) 

但是在 200 万大小的列表输入 1(输入 2 是几千)上运行有点慢(在我的 macbook pro 上超过 10 分钟)。

我找到了一种使用 python 的 multithreading.dummy.Pool 的方法。并使用 pool.map 和一个全局变量来并行化它。但我担心全局变量的使用。这样做安全吗?有没有更好的方法让 python 多线程共享一个变量(可能像 apache spark 的 mapPartions)?

我现在使用的是 Python 2.7。所以我更喜欢使用 python2 来回答。

请您参考如下方法:

由于 GIL,通常建议在需要性能时避免多线程.幸运的是我们有 multiprocessing !

#!/usr/bin/python 
import itertools 
import multiprocessing 
 
in1 = ["foo bar los angles", "foo bar new york",] 
in2 = ["los angles", "new york",] 
 
results = [] 
 
def sub(arg): 
    s1, s2 = arg 
    if s2 in s1: 
        return s1.replace(s2, "") 
 
pool = multiprocessing.Pool(4) 
for result in pool.imap(sub, itertools.product(in1, in2)): 
    if result is not None: 
        results.append(result) 
 
print results 

听起来您的 200 万个项目列表已经在内存中,因此您需要使用 imap 而不是 map 以避免将产品变成数以亿计的项目列表。我还使用 itertools.product 对您的输入进行笛卡尔积运算——这就是您的嵌套循环所做的。

您的要求在唯一性方面有点模糊——您只是在找到匹配项时才添加到结果中。

因为我们只在主体中添加到results,所以不需要担心全局results变量。如果您使用多线程,您的map 函数可以直接写入结果变量,因为有 GIL 的保护....但是您的并发性也会受到 GIL 的影响.

请注意,您可以通过传递较大的 chunksize 来调整 imap。您可以通过使用 imap_unordered 放宽有序要求来进一步优化。参见 multiprocessing获取更多信息。