通过多线程无锁定地将项目添加到同一列表中是否正确?

时间:2019-06-06 10:15:31

标签: python multithreading

这里是详细问题:

我想使用多线程方法来执行批处理http请求,然后将所有这些结果收集到列表中并对所有项目进行排序。

因此,我想首先在主进程中定义一个空列表origin_list,并在将origin_list传递给正常线程之后,启动一些线程以将结果追加到该列表中。

然后我似乎在最后得到了预期的结果,所以我认为我最终得到了正确的结果列表,而没有线程锁定,因为该列表是可变对象,对吗?

我的主要代码如下:

def do_request_work(final_item_list,request_url):
    request_results = request.get(request_url).text
    # do request work
    finnal_item_list.append(request_results )


def do_sort_work(final_item_list):
    # do sort work 
    return final_item_list


def main():

    f_item_list = []
    request_list = [url1, url2, ...]

    with ThreadPoolExecutor(max_workers=20) as executor:
        executor.map(
            partial(
                do_request_work,
                f_item_list
                ),
            request_list)

    sorted_list = do_sort_work(f_item_list)

任何评论都非常受欢迎。非常感谢。

2 个答案:

答案 0 :(得分:1)

我认为,即使不考虑线程安全性,这也是一个非常可疑的解决方案。

首先pythonGIL

  

在CPython中,全局解释器锁或GIL是一个互斥锁,   保护对Python对象的访问,防止多个线程   一次执行Python字节码。

因此,我对这里的性能优势感到怀疑,甚至注意到了

  

可能阻塞或长时间运行的操作,例如I / O,映像   处理,以及NumPy号码处理都发生在GIL之外。

所有python工作将一次执行一个线程。

从另一个角度看,相同的锁可以帮助您确保线程安全,因此一次只有一个线程会修改final_item_list,但我不确定。

无论如何,我在这里使用multiprocessing module和集成的并行map

from multiprocessing import Pool

def do_request_work(request_url):
    request_results = request.get(request_url).text
    # do request work
    return request_results

if __name__ == '__main__':
    request_list = [url1, url2, ...]

    with Pool(20) as p:
        f_item_list = p.map(do_request_work, request_list)

这将保证您并行执行请求的无锁执行,因为每个进程将仅接收其工作的一部分,并在准备就绪时仅返回结果。

答案 1 :(得分:0)

查看此线程:I'm seeking advise on multi-tasking on Python36 platform, Procedure setup

与python3.5 +

有关
Running Tasks Concurrently¶
awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)
Run awaitable objects in the aws sequence concurrently.

我经常使用它,只是要知道它不是线程安全的,所以不要在内部更改值,否则您将使用deepcopy。

要注意的其他事项: