Python队列 - 线程绑定到单个核心

2 投票
2 回答
932 浏览
提问于 2025-04-16 05:25

我写了一个Python脚本,主要做了以下几件事:
1. 提交搜索请求
2. 等待结果
3. 解析返回的结果(XML格式)

我使用了线程和队列模块来并行处理这些任务(设置了5个工作线程)。
在提交搜索请求的部分效果很好,因为我可以同时提交多个搜索任务,并在结果到达时处理它们。
不过,当处理XML数据(这个过程对CPU要求比较高)时,似乎所有的线程都被绑定在同一个核心上,这就造成了性能问题。

有没有人遇到过这个问题?我是不是在理解上有什么遗漏?

另外,我在考虑是否可以设置两个独立的工作队列,一个专门用来提交请求,另一个用来解析XML。目前的做法是一个工作线程同时处理这两项任务。我不太确定这样做是否会有好处。如果有人能提供帮助,我将非常感激。

以下是代码:(去掉了保密数据)

def addWork(source_list):
    for item in source_list:
        #print "adding: '%s'"%(item)
        work_queue.put(item)

def doWork(thread_id):
    while 1:
        try:
            gw = work_queue.get(block=False)
        except Queue.Empty:
            #print "thread '%d' is terminating..."%(thread_id)
            sys.exit() # no more work in the queue for this thread, die quietly

    ##Here is where i make the call to the REST API
    ##Here is were i wait for the results
    ##Here is where i parse the XML results and dump the data into a "global" dict

#MAIN
producer_thread = Thread(target=addWork, args=(sources,))
producer_thread.start() # start the thread (ie call the target/function)
producer_thread.join() # wait for thread/target function to terminate(block)

#start the consumers
for i in range(5):
    consumer_thread = Thread(target=doWork, args=(i,))
    consumer_thread.start()
    thread_list.append(consumer_thread)

for thread in thread_list:
    thread.join()

2 个回答

2

在使用CPython的时候,你的线程其实不会在两个不同的核心上同时运行。你可以查一下全局解释器锁(GIL)的相关信息。

简单来说,GIL就像一个保护锁,确保在执行解释器的代码时,不会有两个线程同时在计算。因此,线程不能并行工作。不过,如果是处理输入输出(I/O)任务,线程就能正常工作,因为这些任务会被阻塞。

补充说明:如果你想充分利用多个核心,就需要使用多个进程。关于这个话题有很多文章,我记得有一篇特别好,但现在找不到了 =/。

正如Nathon所建议的,你可以使用多进程模块。还有一些工具可以帮助你在进程之间共享对象(可以看看POSH,Python对象共享)。

4

这是因为CPython处理线程的方式造成的副作用。网上对此有很多讨论(可以搜索一下GIL),但解决办法是使用multiprocessing模块,而不是threadingMultiprocessing的接口和线程模块差不多(还有同步结构,所以你仍然可以使用队列)。它的特点是给每个线程分配一个完整的进程,这样就避免了GIL和强制串行处理并行任务的问题。

撰写回答