1. 程式人生 > >Python中多程序的使用 Python的多執行緒(threading)與多程序(multiprocessing )示例程式碼 Python多程序程式設計

Python中多程序的使用 Python的多執行緒(threading)與多程序(multiprocessing )示例程式碼 Python多程序程式設計

  • 程序:程式的一次執行(程式載入記憶體,系統分配資源執行)。每個程序有自己的記憶體空間,資料棧等,程序之間可以進行通訊,但是不能共享資訊。
  • 執行緒:所有的執行緒執行在同一個程序中,共享相同的執行環境。每個獨立的執行緒有一個程式入口,順序執行序列和程式的出口。
  • 執行緒的執行可以被強佔,中斷或者暫時被掛起(睡眠),讓其他的執行緒執行。一個程序中的各個執行緒共享同一片資料空間。

       python中的多執行緒其實並不是真正的多執行緒,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多程序。Python提供了非常好用的多程序包multiprocessing,只需要定義一個函式,Python會完成其他所有事情。藉助這個包,可以輕鬆完成從單程序到併發執行

的轉換。multiprocessing支援子程序、通訊和共享資料、執行不同形式的同步,提供了Process、Queue、Pipe、Lock等元件。

多執行緒比較適合IO密集型,不太適合CPU密集型的任務。

#queue 多執行緒各個執行緒的運算的值放到一個佇列中,到主執行緒的時候再拿出來,以此來代替
#return的功能,因為線上程是不能返回一個值的
import time
import threading
from Queue import Queue
 
def job(l,q):
    q.put([i**2 for i in l])
     
def multithreading(data):
    q 
= Queue() threads = [] for i in xrange(4): t = threading.Thread(target = job,args = (data[i],q)) t.start() threads.append(t) for thread in threads: thread.join() results = [] for _ in range(4): results.append(q.get()) print results
if __name__ == "__main__": data = [[1,2,3],[4,5,6],[3,4,3],[5,5,5]] multithreading(data) [[1, 4, 9], [16, 25, 36], [9, 16, 9], [25, 25, 25]]

全域性直譯器鎖GIL(Global Interpreter Lock)

GIL並不是Python的特性,他是CPython引入的概念,是一個全域性排他鎖。

解釋執行python程式碼時,會限制執行緒對共享資源的訪問,直到直譯器遇到I/O操作或者操作次數達到一定數目時才會釋放GIL。   所以,雖然CPython的執行緒庫直接封裝了系統的原生執行緒,但CPython整體作為一個程序,同一時間只會有一個獲得GIL的執行緒在跑,其他執行緒則處於等待狀態。這就造成了即使在多核CPU中,多執行緒也只是做著分時切換而已,所以多執行緒比較適合IO密集型,不太適合CPU密集型的任務。同一時刻一個解釋程序只有一行 bytecode 在執行

多程序

multiprocessing庫彌補了thread庫因為GIL而低效的缺陷。完整的複製了一套thread所提供的介面方便遷移,唯一的不同就是他使用了多程序而不是多執行緒。每個程序都有自己獨立的GIL。但是在windows下多程序的開銷要比多執行緒要大好多,Linux下是差不多的。多程序更加穩定;

建立函式並將其作為單個程序

import multiprocessing
import time

def worker(interval):
    n = 5
    while n > 0:
        print("The time is {0}".format(time.ctime()))
        time.sleep(interval)
        n -= 1

if __name__ == "__main__":
    p = multiprocessing.Process(target = worker, args = (3,))
    p.start()
    print "p.pid:", p.pid
    print "p.name:", p.name
    print "p.is_alive:", p.is_alive()

- 使用執行緒池

# 程序池 ,Pool中是有return的
import multiprocessing as mp

def job(x):
    return x ** 2

def multiprocess():
    pool = mp.Pool()  # 預設是有幾個核就用幾個,可以自己設定processes = ?
    res = pool.map(job, range(10))  # 可以放入可迭代物件,自動分配程序
    print(res)
# apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞,apply(func[, args[, kwds]])是阻塞的 res
= pool.apply_async(job, (2,)) # 一次只能在一個程序裡計算,要達到map的效果,要迭代 print(res.get()) multi_res = [pool.apply_async(job, (i,)) for i in range(10)] # 迭代器 print([res.get() for res in multi_res]) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # 4 # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

- fork操作:呼叫一次,返回兩次。作業系統自動把當前程序複製一份,分佈在父程序和子程序中返回,子程序永遠返回0,父程序永遠返回子程序的ID。子程序getppid()就可以拿到父程序的ID;