<分区> 分区>
我正在尝试使用 ThreadPool 来加速我的代码.
输入是一个包含大约 80000 个元素的字典,每个元素都是 25 个元素的列表。我必须通过处理和组合每个列表中的元素,为字典中的每个元素生成一个输出列表。
所有列表都可以独立分析,因此此设置应该很容易并行化。
这是我用于 pool.map 的基本设置:
from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(NUM_THREADS)
output = pool.map(thread_compute, iterable_list)
pool.close()
pool.join
方法 1(错误):将字典定义为全局字典,并让每个线程获取字典的一个键作为输入。
# in the main global input_dict iterable_list = input_dict.keys() # thread_compute function def thread_compute(key_i): list_to_combine = input_dict[key_i] # call a function processed_list = do_stuff_function(list_to_combine) return processed_list
我很快意识到方法 1 不会工作,因为全局变量 input_dict,即使它从未被写操作访问(因此应该是线程安全的),它受到 GIL 的保护 ( link 1 , link 2 ) - 尝试从单独的线程内安全访问 Python 对象时全局强制执行的锁。
方法 2(无效):我创建了一个包含与
input_dict相同元素的列表,其中每个条目都是 25 个项目的列表。此列表不是全局变量,并且由于GIL,每个线程都应该能够访问一个元素(一个 25 项列表)而不会产生任何开销。# in the main items = list(input_dict.items()) iterable_list = [items[i][1] for i in range(len(items))] # making sure the content is correct assert(len(iterable_list) == len(input_dict)) for i in xrange(len(input_dict.keys())): assert(iterable_list[i] == input_dict[input_dict.keys()[i]]) # thread_compute function def thread_compute(list_of_25_i): # call a function processed_list = do_stuff_function(list_of_25_i) return processed_list
以下是 1、2、4 和 16 个线程的执行时间:
1: Done, (t=36.6810s).
2: Done, (t=46.5550s).
4: Done, (t=48.2722s).
16: Done, (t=48.9660s).
为什么添加线程会导致这样的时间增加?我确信这个问题可以从多线程中获益,并且认为添加线程的开销不能单独对增加负责。
