Python中线程锁的release()方法是否优先被当前线程acquire?
import threading
import time
balance = 0
lock = threading.Lock()
def run_thread(n): global balance
for i in range(100):
lock.acquire()
balance = balance + 1
n = n + balance
time.sleep(1)
print(threading.current_thread().name)
print(n)
print("\r\n\r\n")
lock.release()
t1 = threading.Thread(target=run_thread, args=(5, ), name="t1")
t2 = threading.Thread(target=run_thread, args=(8, ), name="t2")
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)
执行结果: t1 4661
t1 4758
t1 4856
t1 4955
t1 5055 -------------------这儿是 t1 线程已经执行完毕了
t2 109---------------------t2 线程开始执行了
t2 211
t2 314
t1 线程全部走完才会走 t2 线程
Python中线程锁的release()方法是否优先被当前线程acquire?
c 是这样的
我无法理解你的问题
关键这是 python
cpython 底层在 linux 上是用 pthread 库实现的
那这样到底算不算合理?
CPython 有 GIL, 代码是单线程执行的, run_thread 一个线程执行完, 另一个线程才能执行, 跟锁没关系。
gil 只是保证同时只会执行一条语句。并不是需要一个线程彻底执行完才会切换到别的线程
合不合理不重要,重要在于他就是这么做了
本地执行楼主的代码是 t1 t2 交替的。
没加 lock 是交替的,而且里面有错误的数据,但是我本地加上 lock 之后就不是交替执行了
改成这样, 应该就是顺序输出 了. 按你的写法哪个先 acuire lock 不一定。
def run_thread(n):
with lock:
code
好的 我来试试
这样就应该写对了, 多线程抢占的程序的结果比较随机, lock 并没有线程优先取得的问题。
另外 bytecode 的执行 应该是 100 个为单位切换执行
The interpreter releases the GIL every 100 “ticks”.
661 /* for manipulating the thread switch and periodic “stuff” - used to be
662 per thread, now just a pair o’ globals */
663 int _Py_CheckInterval = 100;
Python 的线程虽然是真正的线程,但解释器执行代码时,有一个 GIL 锁:Global Interpreter Lock,任何 Python 线程执行前,必须先获得 GIL 锁,然后,每执行 100 条字节码,解释器就自动释放 GIL 锁,让别的线程有机会执行。这个 GIL 全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在 Python 中只能交替执行
这个应该就是所谓的正解
虽然争夺锁应该是比较随机的,但是在 python 里面由于有 GIL,就和 说的一样,会先执行 100 个单位才开始切换。所以原线程有很大可能又重新获得这个锁吧。
要是刚学 python, 会 C 的话 , 建议直接文档对着源代码看, 免得瞎猜, 浪费时间。https://github.com/python/cpython/blob/master/Python/ceval.c#L1103
谢谢 我是个 phper,对服务器比较感兴趣就学学 python,以后搞服务器方便
多线程编程的第一原则: 不要对行程执行的先后顺序有任何的 assumption。
假设在执行 90 条字节码时,线程阻塞了,此时解释器会自动释放 GIL 锁吗?
释放不了, 需要主动写代码释放, 典型的模式是在阻塞之前释放线程锁, 阻塞操作结束后重新取得。
以 time.sleep()里的这段代码为例,
Py_BEGIN_ALLOW_THREADS
rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE);
Py_END_ALLOW_THREADS
但是在 Python 层面上看,所有会导致阻塞的系统库操作都会让 Python 解析器释放 GIL 锁
是的, 主动释放的, 方法就是下面的, 在底层 C 代码释放的。
Py_BEGIN_ALLOW_THREADS
rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE);
Py_END_ALLOW_THREADS
我现在就在想在直接用 ctypes 调用 c 类库的时候有没有什么办法可释放掉 GIL,因为有些时候并不想为了调用一个简单的 C 类库而去用 CPYTHON C API 写个封装,而 cytpes 类库默认应该是没有释放 GIL 的,所以会导致在一些耗时的操作上限制了多线程能力的发挥
ctypes 调用 c 函数是自动释放 GIL 的, 除非是调用 python 自己的 C API.
821 #ifdef WITH_THREAD
822 if ((flags & FUNCFLAG_PYTHONAPI) == 0)
823 Py_UNBLOCK_THREADS
824 #endif
825 if (flags & FUNCFLAG_USE_ERRNO) {
826 int temp = space[0];
827 space[0] = errno;
828 errno = temp;
829 }
830 #ifdef MS_WIN32
831 if (flags & FUNCFLAG_USE_LASTERROR) {
832 int temp = space[1];
833 space[1] = GetLastError();
834 SetLastError(temp);
835 }
这一段我还真的没有仔细看过,可能是很久前某一篇错误的资料上说他不会自己释放吧


