Skip to main content
 首页 » 编程设计

python之我的 Python 多线程代码是否受全局解释器锁影响

2024年08月22日39jiqing9006

<分区>

我正在尝试使用 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). 

为什么添加线程会导致这样的时间增加?我确信这个问题可以从多线程中获益,并且认为添加线程的开销不能单独对增加负责。