经常遇到小伙伴提到python是单线程的,写代码的时候用多线程没有意义,今天与大家分享一下关于python的单线程与多线程相关理解。
首先 python是单线程的 这句话是不对的。
这里要提到一个概念:Python的全局解释器锁(GIL)
GIL是什么
需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL
帮python洗白了这个冤屈之后我们继续看为什么要用多线程
import threading
import time
def test1():
for i in range(100000000):
a = 100 - i
def test2():
threads = []
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test1)
t3 = threading.Thread(target=test1)
t4 = threading.Thread(target=test1)
threads.append(t1)
threads.append(t2)
threads.append(t3)
threads.append(t4)
threads[0].start()
threads[1].start()
threads[2].start()
threads[3].start()
threads[0].join()
threads[1].join()
threads[2].join()
threads[3].join()
if __name__ == '__main__':
t1 = time.time()
test1()
print('单线程一次:', time.time() - t1) # 单线程一次: 3.872997760772705
test1()
print('单线程两次:', time.time() - t1) # 单线程两次: 7.738230466842651
test1()
print('单线程三次:', time.time() - t1) # 单线程三次: 11.609771013259888
test1()
print('单线程四次:', time.time() - t1) # 单线程四次: 15.493367433547974
t2 = time.time()
test2()
print('多线程四次:', time.time() - t2) # 多线程四次: 15.55045747756958
这段代码执行后会发现4个线程同时执行所消耗的时间与一个线程执行消耗的时间是几乎一样的,到这里有的人会吐槽,这多线程也没提高效率,毛用没有。事实上python多线程在提高效率这块确实毛用没有。因为上边说了,GIL的存在,与单线程处理效率是一样的。
本质是这4个线程交替轮番执行,你执行一会儿,我执行一会儿,他执行一会儿…就是非常和谐的随机在单核上执行
那么问题来了:
是不是python就不需要多线程了呢?
答案是:
需要
追问:
那有啥用呢?
在python里多线程最开始就不是用来解决多核利用率问题的,这个交给操作系统就好了,多线程是解决IO阻塞问题和IO占用时CPU闲置问题。
举个简单的例子:
有一个应用有三个接口:
接口A处理需要花费10s(注意是纯粹的cpu处理消耗时间,不包含网络通信等消耗时间)
接口B处理需要花费5s(注意是纯粹的cpu处理消耗时间,不包含网络通信等消耗时间)
接口C处理需要花费2s(注意是纯粹的cpu处理消耗时间,不包含网络通信等消耗时间)
如果三个用户:小红,小明,小张
几乎同时,小红请求和A接口,小明请求了B接口,小张请求了C接口
单线程下:
小红10s收到结果,小明15s收到结果,小张17s收到结果
小张的接口虽然很快,只需要2s(相对很快),但在单线程上要等前边小红,小明的处理完才能轮到他,所以他要等待17s才能收到结果,小张很郁闷,这么快的方法为啥要等这么长,所以这种设计明显是有问题的。
多线程下:
小红13s收到结果,小明7s收到结果,小张3s收到结果(三个方法交替轮番执行,数值是约等于)
这样虽然都慢一点,但小张和小明还是能接受的
结论:多线程使程序交替轮番执行,不会对后边的程序产生阻塞(这才是python应用多线程的根本目的)
补充:多线程提升不了CPU的处理效率,只能提供调用CPU的方案
所以如果运行瓶颈不在CPU运算而是在IO(网络)上,多线程显然很划算
总结:通常来说,多线程是一个好东西。不过,由于Python的GIL的限制,多线程更适合于I/O密集型应用(I/O释放了GIL,可以允许更多的并发),而不是计算密集型应用。对于后一种情况而言,为了实现更好地并行性,你需要使用多进程,以便让CPU的其他内核来执行。
以上就是我对python应用多线程的理解,有错误和不明确的地方欢迎大家留言!谢谢~