Python學習之旅(二十三)

Python基礎知識(22):進程和線程(Ⅰ)

一、多進程

(1)fork

Python的os模塊封裝了常見的系統調用,其中就包括fork,能夠在Python程序中輕鬆建立子進程python

fork能夠在Mac的Python上運行,但沒法再Windows下運行多線程

(2)multiprocess

multiprocessing模塊就是跨平臺版本的多進程模塊app

multiprocessing模塊提供了一個Process類來表明一個進程對象dom

#process_1.py

from multiprocessing import Process
import os

def work(name):
    print("Run child process %s(%s)..." %(name,os.getpid()))

if __name__=="__main__":
    print("Parent process %s." % os.getpid())
    #建立進程實例
    p = Process(target=work, args=("test",))
    print("Child process will start...")
    p.start()
    p.join()
    print("Child process end.")

結果:
Parent process 14628.
Child process will start...
Child process end.

 

建立子進程時,只須要傳入一個執行函數和函數的參數,建立一個Process實例,用start()方法啓動,join()方法能夠等待子進程結束後再繼續往下運行,一般用於進程間的同步async

(3)pool

用進程池的方式批量建立子進程,啓動大量的子進程函數

#process_2.py

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print("Run task %s(%s)..." %(name,os.getpid()))
    start=time.time()
    time.sleep(random.random()*3)
    end=time.time()
    print("Task &s runs %0.2f seconds." %(name,(end - start)))

if __name__=="__main__":
    print("Parent process %s." % os.getpid())
    p = Pool(2)
    for i in range(3):
        p.apply_async(long_time_task, args=(i,))
    print("Waiting for all subprocess done...")
    p.close()
    p.join()
    print("All subprocess done")

結果:
Parent process 2096.
Waiting for all subprocess done...
All subprocess done

Pool的默認大小是CPU的核數,這次運行環境cup核數爲1spa

(4)子進程

subprocess模塊可讓咱們很是方便地啓動一個子進程,而後控制其輸入和輸出線程

#process_3.py

import subprocess

print("$ nslookup www.python.org")
r = subprocess.call(["nslookup", "www.python.org"])
print("Exit code:", r)


結果:
$ nslookup www.python.org
Exit code: 0

 若是子進程還須要輸入,則能夠經過communicate()方法code

(5)進程間通訊

Python的multiprocessing模塊包裝了底層的機制,提供了QueuePipes等多種方式來交換數據對象

#process_4.py

from multiprocessing import Process, Queue
import os, time, random

def write(q):
    print("Process to write: %s" %os.getpid())
    for value in ["A","B","C"]:
        print("Put %s to queue..." % value)
        q.put(value)
        time.sleep(random.random())

def read(q):
    print("Process to read: %s" % os.getpid())
    while True:
        value = q.get(True)
        print("Get %s from queue." % value)

if __name__=="__mainn__":
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    pw.start()
    pr.start()
    pw.join()
    pr.terminate()

2、多線程

多任務能夠由多進程完成,也能夠由一個進程內的多線程完成

進程是由若干線程組成的,一個進程至少有一個線程

Python的標準庫提供了兩個模塊:_threadthreading_thread是低級模塊,threading是高級模塊,對_thread進行了封裝

絕大多數狀況下,咱們只須要使用threading這個高級模塊

import time, threading

def work():
    n = 1
    while n < 6:
        print("Work %s is running..." % str(n))
        n+=1

t = threading.Thread(target = work, name = "workThread")
t.start()
t.join()
print("%s ended." % threading.current_thread().name)


結果:
Work 1 is running...
Work 2 is running...
Work 3 is running...
Work 4 is running...
Work 5 is running...
MainThread ended.

因爲任何進程默認就會啓動一個線程,咱們把該線程稱爲主線程,主線程又能夠啓動新的線程,Python的threading模塊有個current_thread()函數,它永遠返回當前線程的實例

主線程實例的名字叫MainThread,子線程的名字在建立時指定,名字僅僅在打印時用來顯示,徹底沒有其餘意義,若是不起名字Python就自動給線程命名爲Thread-1Thread-2……

LOCK

線程中,全部變量都由全部線程共享,因此,任何一個變量均可以被任何一個線程修改

線程之間共享數據最大的危險在於多個線程同時改一個變量,把內容給改亂了

當某個進程要更改數據時,先給它上鎖,其它線程不能更改。只有當鎖被釋放後,其它線程得到該鎖之後才能改

因爲鎖只有一個,不管多少線程,同一時刻最多隻有一個線程持有該鎖,因此,不會形成修改的衝突

多核CPU

Python雖然不能利用多線程實現多核任務,但能夠經過多進程實現多核任務。多個Python進程有各自獨立的GIL鎖,互不影響

相關文章
相關標籤/搜索