如何强制执行另一个线程

4 投票
2 回答
4021 浏览
提问于 2025-04-16 04:35

我有一个主线程,它在做一些比较耗CPU的操作。这个线程在进行计算时必须保持一个锁。

然后还有一些其他线程,它们偶尔需要这个锁,但只需要很短的时间。

我该如何让主线程偶尔允许其他线程执行,而不会因为没有其他线程而减慢自己的速度呢?

定期的

lock.release()
time.sleep(x)
lock.acquire()

对于某个x来说,会把控制权交给其他线程,但如果没有其他线程的话,会让主线程变慢。

另一方面,如果没有调用sleep(),全局解释器锁(GIL)似乎会在这里造成干扰。因为主线程在执行release()时持有GIL,所以其他线程显然不能立即从acquire()返回。因此,主线程继续执行自己的acquire()方法,而其他线程除非恰好在我释放锁的时候发生GIL的切换,否则永远无法获得锁。

这个问题的正确解决方案是什么?有没有办法强制释放GIL?基本上,我想要一段神奇的代码,确保在下面的测试脚本中,第二个线程总是先获得锁:

import threading
import time

class t1 (threading.Thread):
    def run(self):
    print "Second thread waiting for lock"
    lock.acquire()
    print "Second thread got lock"
    lock.release()

lock = threading.Lock()
lock.acquire()

t = t1()
t.start()
time.sleep(1)

lock.release()
time.sleep(0) # this works very often, but not all the time
lock.acquire()
print "Main thread got lock"
lock.release()

2 个回答

0

调用 select.select() 并设置超时时间为0,会让全局解释器锁(GIL)暂时释放一下。

4

仅仅释放全局解释器锁(GIL)并不能保证其他线程会有机会运行。

在Unix系统中,你真正想要使用的函数是sched_yield()。不过在Python的标准库里没有这个函数的接口;如果需要的话,可以通过一个本地模块简单地添加这个功能。

usleep(0)select()有时也可以用来达到类似的目的,但根据不同的系统调度器,效果可能会有所不同。在Windows系统中,你应该使用Sleep(0)。对于这两种情况,可以使用time.sleep(0)。

撰写回答