python 的多线程

Python的多线程并非真正并行,由GIL全局解释器锁限制,导致在多核CPU中仅单核运行。GIL的存在是为了线程安全,但引发效率问题。在CPU密集型任务中,多线程可能更慢。解决方案包括使用multiprocessing、修改GIL机制或尝试其他Python解析器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. python的线程

多线程:多线程可以共享本进程中的数据,但是不稳定,如果服务器用多线程来处理可能会因为其中一个线程崩了,而服务器就挂了,相反,多进程一般一个子进程错误,不会导致所有子进程都错误,但是主进程挂了,其他照样都挂。

对于python的多线程实现,其实只是一个线程在跑,不断地进行切换,不是真正的多线程,即使遇到多核cpu,多核cpu只有一个核区发挥其作用,因此,python的多线程用于io密集型的操作中,而在cpu密集型的程序,反而变得更慢。

起因为GIL:

GILIn CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

之所以有GIL这个大坑主要是因为线程安全,python在多线程中为了使其能够实现线程安全,提高其性能,即在多线程下,不会对全局变量或者静态变量进行污染。通过这样的一个锁,使拥有GIL的线程才能运行,在提高性能的同时,效率却下降了,这是Python在效率和性能间的权衡。

可能出现的问题:

1. Python中释放GIL会触发操作系统的一次线程调度,激起后的线程等待被分配GIL,但是,再多核CPU中,如果该线程在其他核心,因为release gil和acquire gil之间的间隙可以说是很短的,大部分情况下很可能刚释放GIL的线程又再次得到GIL。

2. 而这样,被唤醒的线程只能等待,这也一定程度上影响了IO线程(接收到消息时,有一个CPU密集型的线程仍在不断的释放,再次得到GIL)。此外,Python的线程安全并不是绝对安全,怎么感觉GIL还是没什么用,有时候还是会出错,如下面程序:

import threading
import time

t_obj = []
lock = threading.Lock()
num = 0
def run():
    global num
    #lock.acquire() 
    num += 1
    time.sleep(1)     
    num += 1   
    #lock.release()

for i in range(100):
    t = threading.Thread(target = run)
    t_obj.append(t)
    t.start()

for i in t_obj:
    t.join()

print(num)

可以发现,有时候跑出来的结果比正常值小,解决方法是用Python的一个互斥锁(线程锁),这样GIL的意义我就不太清楚是什么

只有lock释放的时候,另外一个线程才能启动。出现结果为198的原因如下:


PythonGIL释放算法是基于pcode(通过计算线程执行的微代码数量来进行GIL的切换),还是基于时间的切换。都有一个可能,程序在运行一半时被强行切换,此时Python将其数据暂时保存在缓冲区中,去执行另外一个线程,而没来得及数据的更新,另一个线程取的数据是没有++过的,而两个线程结果返回到内存时,其实可以说只进行了一次操作。(这里有一个猜想,可能被中途中断保存到缓冲区的线程的优先级比较高,不然的话结果可能偏差很大)

 

 

其实CPYTHON中已经有了一个pthread线程调度算法,这是c语言自己的一个线程调用机制,应该可以理解为GIL是在pthread的上层对其进行管理。

解决方法:

1. 改进Reworking the GIL
– 将切换颗粒度从基于opcode计数改成基于时间片计数(不知道其作用在哪)
– 避免最近一次释放GIL锁的线程再次被立即调度
– 新增线程优先级功能(高优先级线程可以迫使其他线程释放所持有的GIL锁)

2. multiprocess替代Thread缺点为数据共享时将很浪费资源,要通过一个pickle

3. 用其他解析器,其他解析器有的虽然不用GIL,但是其不是用c语言写的,c语言多模块的优势就体现不了(暂时无体会)

 

出处:

1.https://www.zhihu.com/question/23474039 Python多线程的妥协

2.http://blog.youkuaiyun.com/q_l_s/article/details/51538039 IO密集型与CPU密集型,多线程与多进程

3.https://www.zhihu.com/question/21486706 余天升 编译性语言和解释性语言

4.http://python.jobbole.com/81822/    GIL(重点)

5.https://wiki.python.org/moin/GlobalInterpreterLock (英)GIL

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值