7

我正在使用 python 2.7 在 gae 上开发一个应用程序,一个 ajax 调用从 API 请求一些数据,单个请求可能需要大约 200 毫秒,但是当我打开两个浏览器并在非常接近的时间发出两个请求时,它们需要的时间超过双倍,我尝试将所有内容都放在线程中,但它没有工作..(当应用程序在线时会发生这种情况,而不仅仅是在开发服务器上)

所以我写了这个简单的测试来看看这是否是python中的一个问题(在忙等待的情况下),这里是代码和结果:

def work():
    t = datetime.now()
    print threading.currentThread(), t
    i = 0
    while i < 100000000:
        i+=1
    t2 = datetime.now()
    print threading.currentThread(), t2, t2-t

if __name__ == '__main__': 
    print "single threaded:"
    t1 = threading.Thread(target=work)
    t1.start()
    t1.join()

    print "multi threaded:"
    t1 = threading.Thread(target=work)
    t1.start()
    t2 = threading.Thread(target=work)
    t2.start()
    t1.join()
    t2.join()

mac os x, core i7 (4 cores, 8 threads), python2.7上的结果:

single threaded:
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:07.763146
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:13.091614 0:00:05.328468

multi threaded:
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:13.091952
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:13.102250
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:29.221050 0:00:16.118800
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:29.237512 0:00:16.145560

这太令人震惊了!!如果单个线程需要 5 秒来执行此操作.. 我认为同时启动两个线程将需要相同的时间来完成这两个任务,但它几乎需要三倍的时间.. 这使得整个线程的想法毫无用处,因为按顺序进行会更快!

我在这里想念什么..

4

3 回答 3

9

David Beazley在 PyCon 2010 上就这个问题发表了演讲。正如其他人已经指出的那样,对于某些任务,使用线程,尤其是多核,可能会导致性能低于单线程执行的相同任务。Beazley 发现,这个问题与多核的“GIL 战斗”有关:

在此处输入图像描述

为避免 GIL 争用,让任务在单独的进程而不是单独的线程中运行可能会获得更好的结果。多处理模块提供了一种方便的方式来实现这一点,特别是因为多处理 API 与线程 API 非常相似。

import multiprocessing as mp
import datetime as dt
def work():
    t = dt.datetime.now()
    print mp.current_process().name, t
    i = 0
    while i < 100000000:
        i+=1
    t2 = dt.datetime.now()
    print mp.current_process().name, t2, t2-t

if __name__ == '__main__': 
    print "single process:"
    t1 = mp.Process(target=work)
    t1.start()
    t1.join()

    print "multi process:"
    t1 = mp.Process(target=work)
    t1.start()
    t2 = mp.Process(target=work)
    t2.start()
    t1.join()
    t2.join()

产量

single process:
Process-1 2011-12-06 12:34:20.611526
Process-1 2011-12-06 12:34:28.494831 0:00:07.883305
multi process:
Process-3 2011-12-06 12:34:28.497895
Process-2 2011-12-06 12:34:28.503433
Process-2 2011-12-06 12:34:36.458354 0:00:07.954921
Process-3 2011-12-06 12:34:36.546656 0:00:08.048761

PS。正如 zeekay 在评论中指出的那样,GIL 之战只对 CPU 密集型任务很严重。对于 IO-bound 任务来说,这应该不是问题。

于 2011-12-06T17:22:48.417 回答
4

CPython 解释器不允许运行一个以上的线程。阅读 GIL http://wiki.python.org/moin/GlobalInterpreterLock

因此,在 CPython 中,某些任务无法通过线程有效地同时完成。

如果您想在 GAE 中并行执行操作,请使用单独的请求并行启动它们。

此外,您可能想咨询 Python 并行 wiki http://wiki.python.org/moin/ParallelProcessing

于 2011-12-06T17:09:34.100 回答
1

我会看看时间都去哪儿了。例如,假设服务器每 200 毫秒只能回答一个查询。那么你无能为力,每 200 毫秒你只会得到一个回复​​,因为这就是服务器可以为你提供的全部内容。

于 2011-12-06T17:09:54.157 回答