多线程似乎是顺序执行的

13 投票
5 回答
15156 浏览
提问于 2025-04-15 15:47

我在做一个Python项目,想用线程来提高效率,但我发现我的代码里的线程好像没有按预期工作。看起来所有的线程都是一个接一个地运行,也就是说,线程2要等线程1结束后才能开始,它们并没有同时启动。我写了一个简单的脚本来测试这个情况,结果也是线程一个接一个地运行。

import threading

def something():
    for i in xrange(10):
        print "Hello"

def my_thing():
    for i in xrange(10):
        print "world"   

threading.Thread(target=something).start()
threading.Thread(target=my_thing).start() 

这是我运行这个脚本时得到的输出:

Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
world
world
world
world
world
world
world
world
world
world

即使是循环的迭代次数增加,情况也是一样。

我尝试在网上搜索相关信息和以前的回答,但没有找到任何有用的内容。有没有人能告诉我这段代码哪里出问题了?

5 个回答

4

这个行为可能会因为系统是单个处理器还是多个处理器而有所不同,正如David Beazley在这场演讲中所解释的。

正如viraptor所说,第一个线程在执行sys.getcheckinterval()的字节码后会释放全局解释器锁(GIL),默认情况下是100个字节码。简单来说,在单处理器系统上,第二个线程就有机会接管。但是在多核系统上,第二个线程可能会在不同的核心上运行,而第一个线程会尝试重新获取这个锁,通常会成功,因为操作系统还没有时间切换处理器。这意味着在多核系统中,如果有一个线程占用了CPU,其他线程可能就没机会运行了。

解决这个问题的方法是在两个循环中添加一个睡眠语句,这样它们就不再占用CPU了。

11

在第二个线程启动的时间里,第一个线程已经循环并打印出内容了。

这里的情况是这样的,你可以看到第二个线程在第一个线程已经输出了几次“你好”之后才开始运行。

Hello
Hello
Hello
Hello
Hello
Helloworld

Helloworld

Helloworld

Helloworld

Helloworld

world
world
world
world
world

顺便说一下:你的例子其实没有什么意义。线程的主要用途是处理输入输出,而输入输出的速度比较慢。当你加入一些“睡眠”来模拟输入输出时,它应该就能按预期工作了:

import threading
from time import sleep

def something():
    for i in xrange(10):
        sleep(0.01)
        print "Hello"

def my_thing():
    for i in xrange(10):
        sleep(0.01)
        print "world"

threading.Thread(target=something).start()
threading.Thread(target=my_thing).start()

出现了一种奇妙的混合:

worldHello

Helloworld

Helloworld

worldHello

Helloworld

Helloworld

worldHello

Helloworld

worldHello

Helloworld
15

现在在Python中,线程在执行一定数量的字节码指令后会切换。也就是说,它们并不是同时运行的。只有当其中一个线程调用一些需要大量输入输出操作的模块,或者是那些不影响Python的模块时,才能实现线程的并行执行,这样可以释放全局解释器锁(GIL)。

如果你把循环的次数增加到像10000这样的数字,我敢肯定你会发现输出会混在一起。记住,单单启动第二个线程也需要“很多”时间。

撰写回答