python的进程模块
文章目錄
- 進(jìn)程與線程
- 進(jìn)程定義:
- 線程定義
- 線程進(jìn)程的關(guān)系區(qū)別
- 1.直接調(diào)用
- 2.繼承式調(diào)用
- 3.threading.thread實(shí)例方法
- join() :
- 情況1:
- 情況2:
- Daemon() :守護(hù)線程
- 同步鎖
- 死鎖和遞歸鎖
- 事件event
- 信號量(控制同時(shí)可以運(yùn)行的線程)
- 隊(duì)列——多線程利器
- 創(chuàng)建一個(gè)“隊(duì)列”對象
- 生產(chǎn)者消費(fèi)者模型
- 多進(jìn)程模塊multiprocessing
- 每秒鐘運(yùn)行3個(gè)
- show the individual process IDs involved
- Process類
- 進(jìn)程間通信
- 通過隊(duì)列
- 通過管道
- 信息共享 manager
進(jìn)程與線程
假如有兩個(gè)程序A和B,程序A在執(zhí)行到一半的過程中,需要讀取大量的數(shù)據(jù)輸入(I/O操作),而此時(shí)CPU只能靜靜地等待任務(wù)A讀取完數(shù)據(jù)才能繼續(xù)執(zhí)行,這樣就白白浪費(fèi)了CPU資源。是不是在程序A讀取數(shù)據(jù)的過程中,讓程序B去執(zhí)行,當(dāng)程序A讀取完數(shù)據(jù)之后,讓程序B暫停,然后讓程序A繼續(xù)執(zhí)行?當(dāng)然沒問題,但這里有一個(gè)關(guān)鍵詞:切換。
切換,那么這就涉及到了狀態(tài)的保存,狀態(tài)的恢復(fù),加上程序A與程序B所需要的系統(tǒng)資源(內(nèi)存,硬盤,鍵盤等等)是不一樣的。自然而然的就需要有一個(gè)東西去記錄程序A和程序B分別需要什么資源,怎樣去識別程序A和程序B等等,所以就有了一個(gè)叫進(jìn)程的抽象。
進(jìn)程定義:
進(jìn)程就是一個(gè)程序在一個(gè)數(shù)據(jù)集上的一次動態(tài)執(zhí)行過程。
進(jìn)程一般由程序、數(shù)據(jù)集、進(jìn)程控制塊三部分組成。
舉一例說明進(jìn)程:
想象一位有一手好廚藝的計(jì)算機(jī)科學(xué)家正在為他的女兒烘制生日蛋糕。他有做生日蛋糕的食譜,廚房里有所需
的原料:面粉、雞蛋、糖、香草汁等。在這個(gè)比喻中,做蛋糕的食譜就是程序(即用適當(dāng)形式描述的算法)計(jì)算機(jī)科學(xué)家就是處理器(cpu),
而做蛋糕的各種原料就是輸入數(shù)據(jù)。進(jìn)程就是廚師閱讀食譜、取來各種原料以及烘制蛋糕等一系列動作的總和。
現(xiàn)在假設(shè)計(jì)算機(jī)科學(xué)家的兒子哭著跑了進(jìn)來,說他的頭被一只蜜蜂蟄了。計(jì)算機(jī)科學(xué)家就記錄下他
照著食譜做到哪兒了(保存進(jìn)程的當(dāng)前狀態(tài)),然后拿出一本急救手冊,按照其中的指示處理蟄傷。這
里,我們看到處理機(jī)從一個(gè)進(jìn)程(做蛋糕)切換到另一個(gè)高優(yōu)先級的進(jìn)程(實(shí)施醫(yī)療救治),每個(gè)進(jìn)程
擁有各自的程序(食譜和急救手冊)。當(dāng)蜜蜂蟄傷處理完之后,這位計(jì)算機(jī)科學(xué)家又回來做蛋糕,從他
離開時(shí)的那一步繼續(xù)做下去。
線程定義
線程的出現(xiàn)是為了降低上下文切換的消耗,提高系統(tǒng)的并發(fā)性,并突破一個(gè)進(jìn)程只能干一樣事的缺陷,
使到進(jìn)程內(nèi)并發(fā)成為可能。
假設(shè),一個(gè)文本程序,需要接受鍵盤輸入,將內(nèi)容顯示在屏幕上,還需要保存信息到硬盤中。若只有
一個(gè)進(jìn)程,勢必造成同一時(shí)間只能干一樣事的尷尬(當(dāng)保存時(shí),就不能通過鍵盤輸入內(nèi)容)。若有多
個(gè)進(jìn)程,每個(gè)進(jìn)程負(fù)責(zé)一個(gè)任務(wù),進(jìn)程A負(fù)責(zé)接收鍵盤輸入的任務(wù),進(jìn)程B負(fù)責(zé)將內(nèi)容顯示在屏幕上的
任務(wù),進(jìn)程C負(fù)責(zé)保存內(nèi)容到硬盤中的任務(wù)。這里進(jìn)程A,B,C間的協(xié)作涉及到了進(jìn)程通信問題,而且
有共同都需要擁有的東西-------文本內(nèi)容,不停的切換造成性能上的損失。若有一種機(jī)制,可以使
任務(wù)A,B,C共享資源,這樣上下文切換所需要保存和恢復(fù)的內(nèi)容就少了,同時(shí)又可以減少通信所帶
來的性能損耗,那就好了。是的,這種機(jī)制就是線程。
線程也叫輕量級進(jìn)程,它是一個(gè)基本的CPU執(zhí)行單元,也是程序執(zhí)行過程中的最小單元,由線程ID、程序
計(jì)數(shù)器、寄存器集合和堆棧共同組成。線程的引入減小了程序并發(fā)執(zhí)行時(shí)的開銷,提高了操作系統(tǒng)的并發(fā)
性能。線程沒有自己的系統(tǒng)資源。
線程進(jìn)程的關(guān)系區(qū)別
1.Threads share the address space of the process that created it; processes have their own address space. 線程共享創(chuàng)建它的進(jìn)程的地址空間;進(jìn)程們有它們各自的地址空間 2.Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process. 線程們可以直接訪問它的進(jìn)程數(shù)據(jù);進(jìn)程們有它們父進(jìn)程的數(shù)據(jù)拷貝 3.Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes. 線程能夠直接與其進(jìn)程的其他線程交流;進(jìn)程間的交流需要用交互進(jìn)程才能與他們的近鄰進(jìn)程交流 4.New threads are easily created; new processes require duplication of the parent process. 新縣城能容易創(chuàng)建;新進(jìn)程需要復(fù)制父進(jìn)程 5.Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes. 線程可以在同一進(jìn)程的線程上執(zhí)行大量操作;進(jìn)程只能作業(yè)于子進(jìn)程 6.Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes. 對主線程的改變(取消,權(quán)限變更等...)可能會影響同一進(jìn)程的其他線程的表現(xiàn);對父進(jìn)程的改變不會影響子進(jìn)程1.一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.(進(jìn)程可以理解成線程的容器)
2.進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。
3.線程在執(zhí)行過程中與進(jìn)程還是有區(qū)別的。每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
4.進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動,進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.
5.線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧)但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.
6.一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行.
python的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.)
上面的核心意思就是,無論你啟多少個(gè)線程,你有多少個(gè)cpu, Python在執(zhí)行的時(shí)候會淡定的在同一時(shí)刻只允許一個(gè)線程運(yùn)行
python的線程和threading模塊
線程調(diào)用的兩種模式:直接調(diào)用、繼承式調(diào)用
1.直接調(diào)用
import threading import timedef speaksth(num):#定義函數(shù)用于線程運(yùn)行print('start running threading%d' %num)time.sleep(num)if __name__=='__main__':t1 = threading.Thread(target=speaksth,args=(1,))#生成一個(gè)線程實(shí)例t2 = threading.Thread(target=speaksth,args=(2,))#生成另一個(gè)線程實(shí)例t1.start()t2.start()print(t1.getName())#獲取線程名print(t2.getName()) # 獲取線程名print('end'.center(20,'-'))2.繼承式調(diào)用
import threading import timeclass m_thread(threading.Thread):def __init__(self,num,time):self.num = numself.time= timethreading.Thread.__init__(self)def run(self):#定義每個(gè)線程的運(yùn)行函數(shù)print('running on num:%s' %self.num)time.sleep(self.time)print('num:%s end'.center(20,'^') %self.num)if __name__ == '__main__':t1 = m_thread(1,3)t2 = m_thread(2,5)t1.start()t2.start()print("main threading end".center(20,'-'))3.threading.thread實(shí)例方法
.join()要加在線程.start()之后,先線程1.start()主線程一碰到 線程1.join()就停下來等待。
join() :
在子線程完成運(yùn)行之前,這個(gè)子線程的父線程將一直被阻塞。在這個(gè)線程運(yùn)行結(jié)束之前,其他線程等待。
情況1:
import threading from time import ctime,sleep import timedef ListenMusic(name):print("begin listening to %s. %s" %(name,ctime()))sleep(3)print("end listening %s"%ctime()) def RecordBlog(title):print("Begin recording the %s %s" %(title,ctime()))sleep(5)print("end recording %s"%ctime())threads = [] for i in range(5):threads.append(threading.Thread(target=ListenMusic,args=(str(i),)))if __name__ == '__main__':for t in threads:t.start()t.join()print("End main thread %s"%ctime())
即,一個(gè)運(yùn)行完再到另一個(gè)
情況2:
import threading from time import ctime,sleep import time def ListenMusic(name):print("begin listening to %s. %s" %(name,ctime()))sleep(3)print("end listening %s"%ctime()) def RecordBlog(title):print("Begin recording the %s %s" %(title,ctime()))sleep(5)print("end recording %s"%ctime())threads = [] for i in range(5):threads.append(threading.Thread(target=ListenMusic,args=(str(i),)))if __name__ == '__main__':for t in threads:t.start()#t.join()print("End main thread %s"%ctime())Daemon() :守護(hù)線程
setDaemon(True):
將線程聲明為守護(hù)線程,必須在start() 方法調(diào)用之前設(shè)置, 如果不設(shè)置為守護(hù)線程程序會被無限掛起。這個(gè)方法基本和join是相反的。 當(dāng)我們在程序運(yùn)行中,執(zhí)行一個(gè)主線程,如果主線程又創(chuàng)建一個(gè)子線程,主線程和子線程就分兵兩路,分別運(yùn)行,那么當(dāng)主線程完成想退出時(shí),會檢驗(yàn)子線程是否完成。如果子線程未完成,則主線程會等待子線程完成后再退出。但是有時(shí)候我們需要的是只要主線程完成了,不管子線程是否完成,都要和主線程一起退出,這時(shí)就可以用setDaemon方法啦
例子:
一瞬間執(zhí)行完畢,不等子線程運(yùn)行完成。
同步鎖
import time import threading def addNum():global num #在每個(gè)線程中都獲取這個(gè)全局變量#num-=1temp=num#print('--get num:',num )time.sleep(0.1)num =temp-1 #對此公共變量進(jìn)行-1操作num = 100 #設(shè)定一個(gè)共享變量 thread_list = [] for i in range(100):t = threading.Thread(target=addNum)t.start()thread_list.append(t)for t in thread_list: #等待所有線程執(zhí)行完畢t.join()print('final num:', num )
改變time.sleep()的時(shí)間
鎖原理圖:
當(dāng)time.sleep(0.1)變化時(shí) /0.001/0.0000001
多個(gè)線程都在同時(shí)操作同一個(gè)共享資源,所以造成了資源破壞,怎么辦呢?(join會造成串行,失去所線程的意義)
我們可以通過同步鎖來解決這種問題
import time import threading R = threading.Lock()# 同步鎖 def addNum():global num #在每個(gè)線程中都獲取這個(gè)全局變量#num-=1R.acquire()#獲取鎖temp=num#print('--get num:',num )time.sleep(0.0001)num =temp-1 #對此公共變量進(jìn)行-1操作R.release()#解鎖num = 100 #設(shè)定一個(gè)共享變量 thread_list = [] for i in range(100):t = threading.Thread(target=addNum)t.start()thread_list.append(t)for t in thread_list: #等待所有線程執(zhí)行完畢t.join()print('final num:', num )死鎖和遞歸鎖
事件event
An event is a simple synchronization object;the event represents an internal flag,
and threads can wait for the flag to be set, or set or clear the flag themselves.
event = threading.Event()
a client thread can wait for the flag to be set
event.wait()
a server thread can set or reset it
event.set()
event.clear()
If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event.
運(yùn)行結(jié)果:
信號量(控制同時(shí)可以運(yùn)行的線程)
信號量用來控制線程并發(fā)數(shù)的,BoundedSemaphore或Semaphore管理一個(gè)內(nèi)置的計(jì)數(shù) 器,每當(dāng)調(diào)用acquire()時(shí)-1,調(diào)用release()時(shí)+1。
import threading,time class myThread(threading.Thread):def run(self):if semaphore.acquire():print(self.name)time.sleep(2)semaphore.release() if __name__=="__main__":semaphore=threading.Semaphore(5)#每次能運(yùn)行的線程thrs=[]for i in range(100):thrs.append(myThread())for t in thrs:t.start()線程每隔2秒出現(xiàn)5個(gè)
隊(duì)列——多線程利器
保證線程安全。
有線程隊(duì)列也有進(jìn)程隊(duì)列
創(chuàng)建一個(gè)“隊(duì)列”對象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue類即是一個(gè)隊(duì)列的同步實(shí)現(xiàn)。隊(duì)列長度可為無限或者有限??赏ㄟ^Queue的構(gòu)造函數(shù)的可選參數(shù)maxsize來設(shè)定隊(duì)列長度。如果maxsize小于1就表示隊(duì)列長度無限。
將一個(gè)值放入隊(duì)列中
q.put(10)
調(diào)用隊(duì)列對象的put()方法在隊(duì)尾插入一個(gè)項(xiàng)目。put()有兩個(gè)參數(shù),第一個(gè)item為必需的,為插入項(xiàng)目的值;第二個(gè)block為可選參數(shù),默認(rèn)為
1。如果隊(duì)列當(dāng)前為空且block為1,put()方法就使調(diào)用線程暫停,直到空出一個(gè)數(shù)據(jù)單元。如果block為0,put方法將引發(fā)Full異常。
將一個(gè)值從隊(duì)列中取出
q.get()
調(diào)用隊(duì)列對象的get()方法從隊(duì)頭刪除并返回一個(gè)項(xiàng)目。可選參數(shù)為block,默認(rèn)為True。如果隊(duì)列為空且block為True,
get()就使調(diào)用線程暫停,直至有項(xiàng)目可用。如果隊(duì)列為空且block為False,隊(duì)列將引發(fā)Empty異常。
Python Queue模塊有三種隊(duì)列及構(gòu)造函數(shù):
1、Python Queue模塊的FIFO隊(duì)列先進(jìn)先出。 class queue.Queue(maxsize)
2、LIFO類似于堆,即先進(jìn)后出。 class queue.LifoQueue(maxsize)
3、還有一種是優(yōu)先級隊(duì)列級別越低越先出來。 class queue.PriorityQueue(maxsize)
此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回隊(duì)列的大小
q.empty() 如果隊(duì)列為空,返回True,反之False
q.full() 如果隊(duì)列滿了,返回True,反之False
q.full 與 maxsize 大小對應(yīng)
q.get([block[, timeout]]) 獲取隊(duì)列,timeout等待時(shí)間
q.get_nowait() 相當(dāng)q.get(False)
非阻塞 q.put(item) 寫入隊(duì)列,timeout等待時(shí)間
q.put_nowait(item) 相當(dāng)q.put(item, False)
q.task_done() 在完成一項(xiàng)工作之后,q.task_done() 函數(shù)向任務(wù)已經(jīng)完成的隊(duì)列發(fā)送一個(gè)信號
q.join() 實(shí)際上意味著等到隊(duì)列為空,再執(zhí)行別的操作
優(yōu)先級隊(duì)列
import queue import time q = queue.PriorityQueue() #創(chuàng)建隊(duì)列默認(rèn)first in first out,只能存3個(gè)隊(duì)列 q.put([3,12]) q.put([2,'hello']) q.put([4,{'name':'AFf'}]) #q.put(34) #再加這一步會一直卡住,因?yàn)橹荒苡?個(gè) #q.put(34,False) #不會卡住,但是報(bào)錯(cuò)while 1:data = q.get()#隊(duì)列為空時(shí),取不出則報(bào)錯(cuò)time.sleep(1)print(data)生產(chǎn)者消費(fèi)者模型
import queue,threading import time import random q = queue.Queue()def Producer(name):count = 0while count<5:print('begin produce bread')count += 1print('\033[32;1m%s has produced %d bread\033[0m'%(name,count))time.sleep(2)q.put(count)print('round end'.center(20,'-'))def Consumer(name):data = 0while data<5:time.sleep(random.randint(1,2))if q.qsize()>0:print('begin eat bread'.center(20,'^'))data = q.get()print('%s has eat a bread')else:print("-----no baozi anymore----")p1 = threading.Thread(target=Producer,args=('abc',)) c1 = threading.Thread(target=Consumer,args=('guest',)) p1.start() c1.start()多進(jìn)程模塊multiprocessing
Multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency,effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.
每秒鐘運(yùn)行3個(gè)
from multiprocessing import Process import time def f(name):time.sleep(1)print('hello', name,time.ctime())if __name__ == '__main__':p_list=[]for i in range(3):for j in range(3):p = Process(target=f, args=('alvin',))p_list.append(p)p.start()for i in p_list:p.join()print('end')show the individual process IDs involved
from multiprocessing import Process import os import timedef info(title):print("title:", title)print('parent process:', os.getppid())print('process id:', os.getpid())def f(name):info('function f')print('hello', name)if __name__ == '__main__':info('main process line')time.sleep(1)print("------------------")p = Process(target=info, args=('yuan',))p.start()p.join()Process類
構(gòu)造方法:
Process([group [, target [, name [, args [, kwargs]]]]])
group: 線程組,目前還沒有實(shí)現(xiàn),庫引用中提示必須是None;
target: 要執(zhí)行的方法;
name: 進(jìn)程名;
args/kwargs: 要傳入方法的參數(shù)。
實(shí)例方法:
is_alive():返回進(jìn)程是否在運(yùn)行。
join([timeout]):阻塞當(dāng)前上下文環(huán)境的進(jìn)程程,直到調(diào)用此方法的進(jìn)程終止或到達(dá)指定的timeout(可選參數(shù))。
start():進(jìn)程準(zhǔn)備就緒,等待CPU調(diào)度
run():strat()調(diào)用run方法,如果實(shí)例進(jìn)程時(shí)未制定傳入target,這star執(zhí)行t默認(rèn)run()方法。
terminate():不管任務(wù)是否完成,立即停止工作進(jìn)程
屬性:
daemon:和線程的setDeamon功能一樣
name:進(jìn)程名字。
pid:進(jìn)程號。
進(jìn)程間通信
通過隊(duì)列
import time # #import queue #進(jìn)程間的通信不能用線程隊(duì)列 import multiprocessing def foo(q):time.sleep(1)print("son process",id(q))#打印q的idq.put(123)q.put("yuan") if __name__ == '__main__':#q=queue.Queue()q=multiprocessing.Queue()p=multiprocessing.Process(target=foo,args=(q,))#傳一個(gè)進(jìn)程隊(duì)列q過去p.start()#p.join()print("main process",id(q))print(q.get())print(q.get())通過管道
from multiprocessing import Process, Pipe def f(conn):conn.send([12, {"name":"yuan"}, 'hello'])response=conn.recv()print("response",response)conn.close()print("q_ID2:",id(conn))if __name__ == '__main__':parent_conn, child_conn = Pipe() #雙向管道print("q_ID1:",id(child_conn))p = Process(target=f, args=(child_conn,))p.start()print(parent_conn.recv()) #父進(jìn)程等待,如果沒有收到將會阻塞, prints "[42, None, 'hello']"parent_conn.send("兒子你好!")p.join()信息共享 manager
from multiprocessing import Process, Manager def f(d, l,n):d[n] = '1' #{0:"1"}d['2'] = 2 #{0:"1","2":2}l.append(n) #[0,1,2,3,4, 0,1,2,3,4,5,6,7,8,9]#print(l)if __name__ == '__main__':with Manager() as manager:d = manager.dict()#{}l = manager.list(range(5))#[0,1,2,3,4]p_list = []for i in range(10):p = Process(target=f, args=(d,l,i))p.start()p_list.append(p)for res in p_list:res.join()print(d)print(l)參考鏈接:
http://www.cnblogs.com/yuanchenqi/articles/6248025.html
總結(jié)
以上是生活随笔為你收集整理的python的进程模块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win8.1平板安装ubuntu16.0
- 下一篇: ubuntu下载百度网盘文件油猴+ari