Python高阶(一) - 单线程、多线程和多进程的效率对比测试

Python022

Python高阶(一) - 单线程、多线程和多进程的效率对比测试,第1张

线程的目的 - “最大限度地利用CPU资源”。每个程序执行时都会产生一个进程,而每一个进程至少要有一个主线程。对于单CPU来说(没有开启超线程),在同一时间只能执行一个线程,所以如果想实现多任务,那么就只能每个进程或线程获得一个时间片,在某个时间片内,只能一个线程执行,然后按照某种策略换其他线程执行。由于时间片很短,这样给用户的感觉是同时有好多线程在执行。

Python是运行在解释器中的语言,查找资料知道,python中有一个全局锁(GIL),在使用多线程(Thread)的情况下,不能发挥多核的优势。而使用多进程(Multiprocess),则可以发挥多核的优势真正地提高效率。

单线程、多线程和多进程的效率对比测试: github地址

资料显示,如果多线程的进程是CPU密集型的,那多线程并不能有多少效率上的提升,相反还可能会因为线程的频繁切换,导致效率下降,推荐使用多进程;如果是IO密集型,多线程进程可以利用IO阻塞等待时的空闲时间执行其他线程,提升效率。所以我们根据实验对比不同场景的效率

| CPU密集型操作| IO密集型操作| 网络请求密集型操作

-- | -- | --| --

线性操作| 69.73533328374 |17.76633326213 | 6.78833333651

多线程操作| 75.40299995740 |145.68366670609 | 1.93999997775

多进程操作| 13.97433336576 | 4.67833328247| 2.38333328565

仅个人观点,,欢迎留言~~~

因为Python是单线程,所以并行动作是不可能的,以下代码供参考。

from threading import Thread, active_count

from queue import Queue

from turtle import Screen, Turtle

screen = Screen()

a = Turtle('square', visible=False)

a.speed('slow')

a.color('red')

a.penup()

a.setx(-300)

a.setheading(0)

a.pendown()

a.showturtle()

b = Turtle('circle', visible=False)

b.speed('slow')

b.color('green')

b.penup()

b.setx(300)

b.setheading(180)

b.pendown()

b.showturtle()

a.forward(300)

b.forward(300)

screen.mainloop()

def move(turtle):

turtle.forward(1)

if turtle.distance(0, 0) >1:

screen.ontimer(lambda t=turtle: move(t), 50)

move(a)

move(b)

QUEUE_SIZE = 1

def process_queue():

while not actions.empty():

action, *arguments = actions.get()

action(*arguments)

if active_count() >1:

screen.ontimer(process_queue, 100)

actions = Queue(QUEUE_SIZE)

def move(turtle):

while turtle.distance(0, 0) >1:

actions.put((turtle.forward, 1))

Thread(target=move, args=[a], daemon=True).start()

Thread(target=move, args=[b], daemon=True).start()

process_queue()

有必要,至少能解决很多IO阻塞问题。

能产生IO阻塞的情况很多,比如网络、磁盘,等等。当发生阻塞时,Python是不耗CPU的,此时如果就一个线程就没法处理其他事情了。所以对于含有IO阻塞的环境。多线程至少有机会让你把一个CPU核心跑到100%。

另一个用处来自于Python的C扩展模块。在扩展模块里是可以释放GIL的。但释放GIL期间不应该调用任何Python API。所以,对于一些非常繁重的计算,可以写成C模块,计算前释放GIL,计算后重新申请GIL,并将结果返回给Python。这样就可以让Python这个进程利用更多的CPU资源。每个Python的线程都是OS级别pthread的线程。利用Python来管理这些线程比在C层级操作pthread更方便。