python自動化運維之多執行緒

科技小能手發表於2017-11-12

1、Python中的多執行緒

執行一個程式,即在作業系統中開啟了一個程式,在某一時刻,一個CPU核心只能進行一個程式的任務,現在的計算機所說的多程式/多工其實是通過加快CPU的執行速度來實現的,因為一個CPU每秒能執行上億次的計算,能夠對程式進行很多次切換,所以在人為可以感知的時間裡,看上去,計算機確實是在同時執行多個程式,即同時處理多個程式。


一個程式中可以包含有多個執行緒,這多個執行緒為實現該程式的某個主要功能而執行著,多個執行緒可以進行序列工作,也可以併發同時進行工作,顯然後者可以節省更多的時間。


在Python中是支援多執行緒併發執行的,只是Python中的多執行緒只能利用單核,也就是說Python中的某一個程式的多個執行緒只能在一個CPU核心上執行,而不能分配在多個CPU核心中執行,這是考慮到執行緒安全的緣故,而Python中的GIL則保證了執行緒安全。關於Python中的GIL,可以參考文章:《淺析Python的GIL和執行緒安全》。

即GLI是以CPU核心為單位來控制全域性鎖,所以是不能跨不同的CPU(核心 )的

GLI可以保證同一個程式中,某一個執行緒的共享資料在某一時刻只能同時被另外一個執行緒修改(使用),

而不能同時被多個執行緒修改(使用),如果去掉GLI,則需要自己為執行緒加鎖,這樣之後,效能比原來還要差。

當然,難道就不能充分利用多核CPU或多個CPU了?

做成多程式就可以了,不同的程式執行在不同的CPU(核心)上,也可以實現併發,

只是這樣的話就會比較浪費記憶體空間,考慮同時執行10個QQ程式的情況,

假如1個QQ佔用500M的記憶體空間,則10個QQ就要佔用5G的記憶體空間了。但如果是多執行緒的話,

可能10個QQ還是共享著這500M的記憶體空間。還有一個缺點就是,多程式間的資料直接訪問可能

會比較麻煩,但其實也是可以實現的,比如chrome瀏覽器就是用多程式實現的。

目前首先要明確的是,Python中是不能把一個程式的多個執行緒分佈在不同的CPU核心上執行的。
2、Python多執行緒使用方法1

給出下面的程式程式碼及註釋:

1
2
3
4
5
6
7
8
import threading    # Python多執行緒模組
import time
def run(num):
    print(`Hi, I am thread %s..lalala` % num)
     time.sleep(20)
for in range(20):
    t = threading.Thread(target=run, args=(i,))   # 多執行緒使用方法,target為需要執行多執行緒的函式,args為函式中的引數,注意這裡的引數寫成(i,),即如果只能一個引數,也要加上一個","
    t.start()    # 開始執行多執行緒

執行結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Hi, I am thread 0..lalala
Hi, I am thread 1..lalala
Hi, I am thread 2..lalala
Hi, I am thread 3..lalala
Hi, I am thread 4..lalala
Hi, I am thread 5..lalala
Hi, I am thread 6..lalala
Hi, I am thread 7..lalala
Hi, I am thread 8..lalala
Hi, I am thread 9..lalala
Hi, I am thread 10..lalala
Hi, I am thread 11..lalala
Hi, I am thread 12..lalala
Hi, I am thread 13..lalala
Hi, I am thread 14..lalala
Hi, I am thread 15..lalala
Hi, I am thread 16..lalala
Hi, I am thread 17..lalala
Hi, I am thread 18..lalala
Hi, I am thread 19..lalala

直接看執行結果是看不出什麼的,這裡說一下這個程式的執行過程:0到19是同時列印輸入的,在列印19後,程式sleep 1秒後才結束程式的執行。

上面這個程式有20個執行緒執行,每個執行緒都是:列印字串+sleep(20)。我們實際看到的結果是0到19同時列印,然後才sleep 20秒,但是需要注意的是,並非是20個執行緒才執行一次sleep(20),而是在每個執行緒中都執行了一次sleep(20),即該程式實際上是執行了20次sleep(20),而我們實際看到的結果是程式執行時僅僅是暫停了1秒,那是因為這20次sleep(20)是併發執行的。

上面的程式可以這麼去理解:20個執行緒相當於有20匹馬,20匹馬同時起跑(列印字串),然後以同時停20秒(sleep(20)),最後同時到達終點(20個執行緒執行結束,即程式執行結束)。

為了更好的理解上面的程式,可以把上面的程式碼改為如下:

1
2
3
4
5
6
7
8
9
import threading
import time
def run(num):
    print(`Hi, I am thread %s..lalala` % num)
    time.sleep(20)
for in range(20):
    t = threading.Thread(target=run, args=(i,))
    t.start()
    t.join()    #等上一個執行緒執行完後再執行下一個執行緒

執行結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Hi, I am thread 0..lalala
Hi, I am thread 1..lalala
Hi, I am thread 2..lalala
Hi, I am thread 3..lalala
Hi, I am thread 4..lalala
Hi, I am thread 5..lalala
Hi, I am thread 6..lalala
Hi, I am thread 7..lalala
Hi, I am thread 8..lalala
Hi, I am thread 9..lalala
Hi, I am thread 10..lalala
Hi, I am thread 11..lalala
Hi, I am thread 12..lalala
Hi, I am thread 13..lalala
Hi, I am thread 14..lalala
Hi, I am thread 15..lalala
Hi, I am thread 16..lalala
Hi, I am thread 17..lalala
Hi, I am thread 18..lalala
Hi, I am thread 19..lalala

執行結果看上去跟前面是一樣的,但執行過程卻是這樣的:每列印一次字串,再暫停20秒。

通過這個程式,也就可以更好的理解Python的多執行緒併發執行了,當然,因為這是一個動態的過程,所以把程式執行一遍後會有更好的理解。
3、Python多執行緒使用方法2

1
2
3
4
5
6
7
8
9
10
11
import threading,time
class MyThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num
    def run(self): #this name must be `run`
        print(`I am thread %s` % self.num)
        time.sleep(2)
for in range(20):
    t = MyThread(i)
    t.start()

程式的執行結果與方法1是一樣的,這裡就不給出了,只是這裡利用了物件導向程式設計的思想方法來設計程式程式碼。

本文轉自 炫維 51CTO部落格,原文連結:http://blog.51cto.com/xuanwei/1961458


相關文章