1. 程式人生 > >python中程序和執行緒

python中程序和執行緒

為什麼要用程序和執行緒

多執行緒是程式設計過程中經常會使用到的手段,其目的是為了能提高任務執行的效率,很多時候系統都需要建立多個程序以提高CPU的利用率,當數量較少時,可以手動生成一個個Process例項。當程序數量很多時,或許可以利用迴圈,但是這需要程式設計師手動管理系統中併發程序的數量,有時會很麻煩。雖然Python多執行緒有缺陷,總被人說成是雞肋,但也不是一無用處,它很適合用在IO密集型任務中。I/O密集型執行期間大部分是時間都用在I/O上,如資料庫I/O,較少時間用在CPU計算上。因此該應用場景可以使用Python多執行緒,當一個任務阻塞在IO操作上時,我們可以立即切換執行其他執行緒上執行其他IO操作請求。

process 程序

1、process概念:程序是由一段程式碼程式組成的應用程式,其在執行時作業系統會分配給該程序獨立的系統資源(記憶體)

2、多程序的執行:在作業系統中,通常採用“時間片輪轉法”的策略,來實現應用程式(程序)的並行。當一個應用程式在作業系統中執行時,作業系統會自動給該程序分配一個ID,用來唯一標識該程序

import os
from multiprocessing import Process

def run_proc(name):
    print('執行的子程式(%s)' %os.getpid())

if __name__ == '__main__':
    print('父程序的程序ID(%s)' % os.getpid())
    p = Process(target=run_proc,args=('test',))
    print('子程序開始執行')
    p.start()
    p.join()
    print('子程序結束')


Thread

3、執行緒的概念:執行緒是不能夠獨立存在於作業系統中,需要依賴於程序的存在。在python中,一個程序至少有一個主執行緒(mainthread)。多程序和多執行緒都可以執行多個任務,執行緒是程序的一部分。執行緒的特點是執行緒之間可以共享記憶體和變數,資源消耗少(不過在Unix環境中,多程序和多執行緒資源排程消耗差距不明顯,Unix排程較快),缺點是執行緒之間的同步和加鎖比較麻煩。那麼多個執行緒同時共享同一個程序的資源。

4、執行緒的實現:

在python中執行緒的實現,根據不同的作業系統來區分:

1)Linux/Unix/Mac:python 通過呼叫os模組中的fork()函式,進行建立子程序。

2)windows:python通過呼叫multiprocessing模組,來實現。

3)程序的執行:在oython程式中,我們通過例項化一個Process程序物件,

程式碼如下:

p = Process(target=run_proc,args=('test',))其中,target用來指定程序的功能,args指定程序的名稱等內容。

注意:此時程序已經具備了可以執行的相關軟體,但還未執行。在呼叫了start()函式後,該程序開始執行,如果遇到join()函式,表示該程序會被掛起(等待)

直到其他子程序執行完畢後,再執行自身未完成的內容。

當程序執行完畢後,或出現異常時,程序即結束。不需要我們進行人工干預。

import threading
import time
 
def target():
    print 'the curent threading  %s is running' % threading.current_thread().name
    time.sleep(1)
    print 'the curent threading  %s is ended' % threading.current_thread().name
 
print 'the curent threading  %s is running' % threading.current_thread().name
t = threading.Thread(target=target)
 
t.start()
t.join()
print 'the curent threading  %s is ended' % threading.current_thread().name
 
輸出:
the curent threading  MainThread is running
the curent threading  Thread-1 is running
the curent threading  Thread-1 is ended
the curent threading  MainThread is ended

start是啟動執行緒,join是阻塞當前執行緒,即使得在當前執行緒結束時,不會退出。從結果可以看到,主執行緒直到Thread-1結束之後才結束。 Python中,預設情況下,如果不加join語句,那麼主執行緒不會等到當前執行緒結束才結束,但卻不會立即殺死該執行緒。如不加join輸出如下:

the curent threading  MainThread is running
the curent threading  Thread-1 is running
 the curent threading  MainThread is ended
the curent threading  Thread-1 is ended

但如果為執行緒例項新增t.setDaemon(True)之後,如果不加join語句,那麼當主執行緒結束之後,會殺死子執行緒。程式碼:

import threading
import time
def target():
    print 'the curent threading  %s is running' % threading.current_thread().name
    time.sleep(4)
    print 'the curent threading  %s is ended' % threading.current_thread().name
print 'the curent threading  %s is running' % threading.current_thread().name
t = threading.Thread(target=target)
t.setDaemon(True)
t.start()
t.join()
print 'the curent threading  %s is ended' % threading.current_thread().name
輸出如下:
the curent threading  MainThread is running
the curent threading  Thread-1 is runningthe curent threading  MainThread is ended

如果加上join,並設定等待時間,就會等待執行緒一段時間再退出:

import threading
import time
def target():
    print 'the curent threading  %s is running' % threading.current_thread().name
    time.sleep(4)
    print 'the curent threading  %s is ended' % threading.current_thread().name
print 'the curent threading  %s is running' % threading.current_thread().name
t = threading.Thread(target=target)
t.setDaemon(True)
t.start()
t.join(1)
輸出:
the curent threading  MainThread is running
the curent threading  Thread-1 is running
the curent threading  MainThread is ended

主執行緒等待1秒,就自動結束,並殺死子執行緒。如果join不加等待時間,t.join(),就會一直等待,一直到子執行緒結束,輸出如下:

the curent threading  MainThread is running
the curent threading  Thread-1 is running
the curent threading  Thread-1 is ended
the curent threading  MainThread is ended

5、執行緒的執行機制:

1)首先,python虛擬機器,設定GIL(全域性解釋鎖)。供呼叫相關資源的執行緒使用。

2)然後,呼叫相關的執行緒,該執行緒會獲得鎖的持有權,對需要呼叫的資源進行上鎖。

3)進行相關程式碼功能的執行後,主動讓出鎖的控制權,比如:sleep

4)執行緒進入休眠狀態

5)切換下一個執行緒,繼續重複上述步驟。

生產者-消費者問題: 1、簡單實現

import threading
import time
product = None #社會商品
condition = threading.Condition()#條件變數,用來判斷是否繼續生產或消費


def producer():#生產者
    global product
    if condition.acquire():#判斷是否獲的了鎖
        while True:
            if product is None:
                print('生產中。。。。。')
                product = 'anything'
                condition.notify() #通知消費者,商品已經生產完畢
            condition.wait()#等待消費者的生產通知
            time.sleep(2)


def consumer():#消費者
    global product
    if condition.acquire():#判斷是否獲的了鎖
        while True:
            if product is not None:
                print('消費中.....')
                product = None
                condition.notify()#通知生產者,已經消費完畢
            condition.wait()#等待生產者的消費通知
            time.sleep(2)


t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)
t2.start()
t1.start()

結果:

父程序的程序ID(6548)
子程序開始執行
執行的子程式(6440)
子程序結束

在Python中,有一個GIL,即全域性解釋鎖,該鎖的存在保證在同一個時間只能有一個執行緒執行任務,也就是多執行緒並不是真正的併發,只是交替得執行。

GIL的全稱是Global Interpreter Lock(全域性直譯器鎖),來源是python設計之初的考慮,為了資料安全所做的決定。某個執行緒想要執行,必須先拿到GIL,我們可以把GIL看作是“通行證”,並且在一個python程序中,GIL只有一個。拿不到通行證的執行緒,就不允許進入CPU執行。GIL只在cpython中才有,因為cpython呼叫的是c語言的原生執行緒,所以他不能直接操作cpu,只能利用GIL保證同一時間只能有一個執行緒拿到資料。而在pypython和jpython中是沒有GIL的。

雖然Python的多執行緒多被詬病但是Python多執行緒在IO密集型任務中還是很有用處的,而對於計算密集型任務,應該使用Python多程序。