【问题标题】:threading appears to run threads sequentially线程似乎按顺序运行线程
【发布时间】:2009-11-08 19:11:07
【问题描述】:

我正在尝试在我正在处理的 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

循环的迭代次数更多时观察到相同的行为。

我尝试搜索网络和较旧的 SO 答案,但找不到任何帮助。 有人可以指出这段代码有什么问题吗?

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    目前在 python 中,线程在执行一定数量的字节码指令后会发生变化。它们不会同时运行。只有当其中一个线程调用一些 I/O 密集型或非影响 Python 的可释放 GIL(全局解释器锁)的模块时,您才会让线程并行执行。

    我敢肯定,如果将循环数增加到 10000 次左右,您会混淆输出。请记住,简单地生成第二个线程也需要“很多”时间。

    【讨论】:

    • 10000 次迭代的相同行为
    • 在我正在处理的实际项目中,其中一个线程是一个无限循环,它侦听消息并在消息到达时调用回调函数。它只是阻塞所有其他线程。不幸的是,无法修改实际的循环代码(我只是在线程内调用了一个类的 run() 方法)。
    • 当我像这样运行脚本时:./pythr.py | uniq -c 我得到:8969 1 你好世界 | 6626世界 | 1 | 3373世界 | 1030 你好。所以它确实改变了控制——只是不那么频繁......
    • 解决此问题的另一种方法是使用multiprocessing 插入threading 模块。这样您的代码实际上是并行运行的。
    • 谢谢。多处理解决了我的项目代码中的问题。
    【解决方案2】:

    在第二个线程启动第一个线程循环和打印的时间里。

    这里看起来像这样,你可以看到第二个线程在第一个发出几个 hellos 之后开始。

    Hello
    Hello
    Hello
    Hello
    Hello
    Helloworld
    
    Helloworld
    
    Helloworld
    
    Helloworld
    
    Helloworld
    
    world
    world
    world
    world
    world
    

    顺便说一句:你的例子根本没有意义。 Threads 的唯一原因是 IO,而且 IO 很慢。当您添加一些 sleep 来模拟 IO 时,它应该可以按预期工作:

    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
    

    【讨论】:

    • 即使 for 循环的迭代次数更多/更少,我也不会得到这样的输出。在我的电脑上,它总是顺序的。正如 abyx 所建议的,我认为这取决于操作系统/处理器。
    • 正如我在问题中所说,这只是我的问题的一个示例,而不是我正在使用的代码(它要大得多)。在我的实际代码中,其中一个线程运行一个循环监听 dbus 信号。
    【解决方案3】:

    根据系统使用的是单个处理器还是多个处理器,行为也可能发生变化,正如 David Beazley 的 this talk 所解释的那样。

    正如 viraptor 所说,第一个线程将在执行 sys.getcheckinterval() 字节码(默认为 100)后释放 GIL。粗略地总结一下 David Beazley 所说的,在单处理器系统上,第二个线程将有机会接管。然而,在多核系统上,第二个线程可能在不同的核心上运行,第一个线程将尝试重新获取锁,并且可能会成功,因为操作系统没有时间切换处理器。这意味着在具有 CPU 绑定线程的多核系统上,其他线程可能永远无法查看。

    解决方法是在两个循环中添加一个 sleep 语句,以便它们不再受 CPU 限制。

    【讨论】:

      【解决方案4】:

      这实际上取决于您的操作系统的调度程序,您的处理器。
      除此之外,众所周知,CPython 的线程并不完美,因为GIL(PDF),简而言之,这意味着很多时候线程确实是按顺序运行的,或者类似的东西。

      【讨论】:

      • 您的意思可能是 CPython 线程受到 GIL 的影响……比如 Jython 中没有 GIL。
      猜你喜欢
      • 1970-01-01
      • 2012-05-08
      • 2018-10-01
      • 2016-03-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多