グローバルインタプリタロック--GILスレッド限りネットワークプログラミング

グローバルインタプリタロック--GILスレッド限りネットワークプログラミング

まず、プライマー

定义:
In 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.)

结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

まずクリアする必要がPythonのGIL特性ではない、それが導入されたPythonのパーサ(CPythonと)の実装時の概念です。これは、C ++言語のような(文法)標準であるが、実行可能なコードに別のコンパイラであってもよいです。このようようにGCC、インテルC ++は、Visual C ++ととしてよく知られているコンパイラ。Pythonは同じであり、コードの同じ部分を異なる実行することによって実行することができるようにPythonのCPythonの、PyPy、サイコを環境。何GILはありませんJPythonのように。しかし、CPythonのは、ほとんどの環境Pythonの実行環境下のデフォルトです。CPythonのPythonは多くの人々の概念であるので、GIL Python言語に起因する欠陥を仮定します。そこでここではまず明確にする必要があります:GILは、PythonはGILに頼ることができない、Pythonの機能ではありません。

二、GIL導入

GILは、すべてのミューテックスの本質であるので、本質的に、ミューテックス、ミューテックスで同一であり、全てなるシリアルが同時に実行され、同じ時間内でのデータの共有を制御するためにのみタスクによって修飾することができます、したがって、データのセキュリティを確保します。

異なるデータの安全性を守るために、あなたは別のロックを追加する必要がありますのを確認するためには、このです。

最初に一つのことを決定、GILを理解するには、次の各時間のpythonプログラムを、それが別のプロセスを持つことになります。例えばのpython test.py、Pythonのaaa.py、Pythonのbbb.pyは、3つの異なるプロセスパイソンが生成されます

唯一のプロセスを作るのpython test.pyを確認します。

#test.py内容
import os,time
print(os.getpid())
time.sleep(1000)
#打开终端执行
python3 test.py
#在windows下查看
tasklist |findstr python
#在linux下下查看
ps aux |grep python

だけでなく、インタプリタレベルtest.pyはメインスレッド又は他のスレッドChengkaiチー本線から、ならびにインタプリタスレッド短い、すべてのスレッドでは、ガベージコレクション、等オンプロセスでPythonは、このプロセスで実行されています内部には、間違いなく。

1、所有数据都是共享的,这其中,代码作为一种数据也是被所有线程共享的(test.py的所有代码以及Cpython解释器的所有代码)
例如:test.py定义一个函数work(代码内容如下图),在进程内所有线程都能访问到work的代码,于是我们可以开启三个线程然后target都指向该代码,能访问到意味着就是可以执行。

2、所有线程的任务,都需要将任务的代码当做参数传给解释器的代码去执行,即所有的线程要想运行自己的任务,首先需要解决的是能够访问到解释器的代码。

要約すると:

ターゲット=仕事の複数のスレッドは、プロセスが実行される場合

複数のスレッドが最初のコードを実行するターゲット・コード・インタプリタに、その後の許可を取得するために実行されるインタプリタコードを訪問し、

インタプリタコードは、すべてのスレッドで共有されているので、ガベージコレクタスレッドはまた、質問につながる、離れインタプリタコードの実行へのアクセスを有することができる、同じデータ100を同時にスレッド1のx = 100を実行すること、及びガベージコレクションは、リカバリ操作100に巧妙な方法によって行われ、この問題が解決されていない、すなわち、ロック処理であり、GILに示すように、タスクは、コードを実行することができると同時に、Pythonのインタープリターを確保します。

三、GILとロック

機知に富んだ学生は、この質問をするかもしれません:Pythonは1つのスレッドしか実行することを確実にするGIL同じ時間を持って、そこにもあるロックする必要がなぜですか?

まず、我々は合意に達する必要があります:ロックの目的は一つだけのスレッドが同時に、共有データを保護することである共有データを変更します

異なるデータ保護が異なるロックに追加する必要があります。そこで、我々は、と結論付けることができます。

、GILとロックが2つのロック、データの保護が保護されており、(もちろん、そのようなデータのガベージコレクションとしてインタプリタレベルのデータを、保護することです)、元通訳レベル、同じではありませんが、問題となっている。最後に、それは明らかですユーザ独自のアプリケーション開発のデータ、GILは唯一のロックは、以下に示すように、ユーザー定義のロックを扱うことができ、この問題の責任ではないことは明らかです。

分析:

1、100个线程去抢GIL锁,即抢执行权限
2、肯定有一个线程先抢到GIL(暂且称为线程1),然后开始执行,一旦执行就会拿到lock.acquire()
3、极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL,然后开始运行,但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL
4、直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock,然后其他的线程再重复2 3 4的过程

デモ:

from threading import Thread,Lock
import os,time
def work():
    global n
    lock.acquire()
    temp=n
    time.sleep(0.1)
    n=temp-1
    lock.release()
if __name__ == '__main__':
    lock=Lock()
    n=100
    l=[]
    for i in range(100):
        p=Thread(target=work)
        l.append(p)
        p.start()
    for p in l:
        p.join()
    print(n) #结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全,不加锁则结果可能为99

四、GILとマルチスレッド

GILの存在と、同じ時間に同じプロセスは、ただ1つのスレッドが実行されます。

これを聞いて、一部の学生はすぐに尋ねた:プロセスは、マルチコアを活用することができますが、大きなオーバーヘッド、およびPythonは小さなオーバーヘッドをマルチスレッド化が、それは無用のpythonで、マルチコア利点を活用することができませんでした、PHPは言語のベストです?

まだ終わっていない、心配しないでください。

この問題を解決するために、我々はいくつかの点に同意する必要があります。

1、cpu到底是用来做计算的,还是用来做I/O的?
2、多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能
3、每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处

I / Oの作業者に必要な原料を提供するために、ブロッキングプロセスに対応する、職場で従業員に相当し、ない場合は原料を処理する作業者は、プロセスは作業者のためのものであるこの時点で計算され、作業者のCPUに対応私たちは、原材料の到着まで待つ、停止する必要があります。

タスクの大半は、あなたが(I / O集中型)工場乾燥原料調製工程を持っている必要があります場合は、より多くの労働者を持っており、非常に有意義なことではない、プロセスの労働者、そのような材料としてそのように人を好きではありませんそれ以外の場合は、ライブすることができません。

逆に、あなたは原材料が完了している植物の場合は、当然のことながら、より多くのことを労働者、より効率的です

結論:

1、对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用
2、当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,从而进一步分析python的多线程到底有无用武之地

私たちは4つのタスクは、ソリューションをすることができ、治療は間違いなく同時エフェクトを再生する必要があります対処する必要があるとします。

方案一:开启四个进程
方案二:一个进程下,开启四个线程

シングルコアの場合、結果:

1、如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
2、如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜

結論:

现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

第五に、マルチスレッド性能試験

複数の同時タスクは計算集約されている場合:高効率マルチプロセス

from multiprocessing import Process
from threading import Thread
import os,time
def work():
    res=0
    for i in range(100000000):
        res*=i
if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(4):
        p=Process(target=work) #耗时5s多
        p=Thread(target=work) #耗时18s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

複数の同時タスクは、I / O集中型の場合:高効率マルチスレッド

from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
    time.sleep(2)
    print('===>')
if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(400):
        # p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
        p=Thread(target=work) #耗时2s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

アプリケーション:

1、多线程用于IO密集型,如socket,爬虫,web
2、多进程用于计算密集型,如金融分析

おすすめ

転載: www.cnblogs.com/Kwan-C/p/11589756.html