剖析python多线程对多核cpu的利用

我们经常听到"因为GIL的存在,python的多线程不能利用多核CPU",现在我们暂且不提GIL,python能不能利用多核cpu,今天我做了一个实验,代码很简单如下所示

while 1:
    pass

没有运行这段代码前,cpu状态如下
剖析python多线程对多核cpu的利用_第1张图片
image.png

下面两张图是运行之后的状态,当然这只是两张比较有代表性的图,截图间隔有十几秒的样子

剖析python多线程对多核cpu的利用_第2张图片
image.png
剖析python多线程对多核cpu的利用_第3张图片
image.png

根据第一张图我们发现cpu1、cpu3的负载有明显增长,我们可以得出python线程是可以利用多核cpu的结论,之前一直以为python运行后会绑定cpu其中的一个核心现在看来并不是这个样子。第二张图就比较有意思了cpu2满载了,这又是为什么呢?想来想去应该是linux中cpu对进程的亲和性导致的,这种亲和性是软性的并不是强制的,这也就解释了为什么第一张图中是多cpu在负载。

ok为了更直观的看出python线程能够利用多核cpu,我们改下代码,换一种方式再来看下

import os

while 1:
    print os.getpid() # 输出进程号

运行代码结果如下
剖析python多线程对多核cpu的利用_第4张图片
image.png

一目了然,线程的确在不同的核心上切换。

现在我们回过头看下那句经典的话"因为GIL的存在,python的多线程不能利用多核CPU",这句话很容易让人理解成GIL会让python在一个核心上运行,有了今天的例子我们再来重新理解这句话,GIL的存在让python在同一时刻只能有一个线程在运行,这毋庸置疑,但是它并没有给线程锁死或者说指定只能在某个cpu上运行,另外我需要说明一点的是GIL是与进程对应的,每个进程都有一个GIL。python线程的执行流程我的理解是这样的
线程 ——>抢GIL——>CPU
这种执行流程导致了CPU密集型的多线程程序虽然能够利用多核cpu时跟单核cpu是差不多的,并且由于多个线程抢GIL这个环节导致运行效率<=单线程。看到这可能会让人产生一种错觉,有了GIL后python是线程安全的,好像根本不需要线程锁,而实际情况是线程拿到CPU资源后并不是一直执行的,python解释器在执行了该线程100条字节码(注意是字节码不是代码)时会释放掉该线程的GIL,如果这时候没有加锁那么其他线程就可能修改该线程用到的资源; 另外一个问题是遇到IO也会释放GIL,下面是这两种情况的例子

import threading


a = []


def m1():
    for _ in range(100000):
        a.append(1)


def m2():
    for _ in range(100000):
        a.append(2)


def check():
    """
    检查a是否有序
    """
    for i in range(len(a)):
        if i != 0:
            if a[i] < a[i-1]:
                print a[i-1], a[i]
                return False
    return True


t1 = threading.Thread(target=m1)
t2 = threading.Thread(target=m2)


t1.start()
t2.start()
t1.join()
t2.join()

print check()

预期1111...22222...,截图显示跟预期的不同
image.png
import threading

text1 = '1' * 10000
text2 = '2' * 10000


def write(text):
    with open('test.txt', 'a') as f:
        f.write(text)


def m1():
    write(text1)


def m2():
    write(text2)


t1 = threading.Thread(target=m1)
t2 = threading.Thread(target=m2)

t1.start()
t2.start()

t1.join()
t2.join()

test.txt截图
image.png

最后结论是,因为GIL的存在,python的多线程虽然可以利用多核CPU,但并不能让多个核同时工作。

你可能感兴趣的:(剖析python多线程对多核cpu的利用)