多任務(wù)-進程

一肢簿、進程及狀態(tài)

1. 進程

程序:比如電腦安裝了很多程序,又比如我們編寫一個xxx.py程序深浮,它們靜靜的保存在硬盤中压怠,所以程序是一個靜態(tài)的概念。
進程:一個程序運行起來后飞苇,代碼+用到的資源 稱之為進程菌瘫,它是操作系統(tǒng)分配資源的基本單位。
不僅可以通過線程完成多任務(wù)布卡,進程也是可以的雨让。

2. 進程的狀態(tài)

工作中,任務(wù)數(shù)往往大于cpu的核數(shù)虚汛,即一定有一些任務(wù)正在執(zhí)行,而另外一些任務(wù)在等待cpu進行執(zhí)行,因此導(dǎo)致了有了不同的狀態(tài)。
就緒態(tài):運行的條件都已經(jīng)滿足襟诸,正在等在cpu執(zhí)行
執(zhí)行態(tài):cpu正在執(zhí)行其功能
等待態(tài):等待某些條件滿足陷揪,例如一個程序sleep了耐量,此時就處于等待態(tài)劲藐,紅綠燈汰现,等待消息回復(fù),等待同步鎖 等都是處于等待態(tài)

二妄田、進程的創(chuàng)建-multiprocessing

multiprocessing模塊就是跨平臺版本的多進程模塊俺亮,提供了一個Process類來創(chuàng)建進程對象。

1.示例如下:

from multiprocessing import Process
import time

def run_proc():
  """子進程要執(zhí)行的代碼"""
  while True:
    print("----2----")
    time.sleep(1)


if  __name__  == '__main__':
    p = Process(target=run_proc)
    p.start()
    while True:
        print("----1----")
        time.sleep(1)
創(chuàng)建子進程時疟呐,只需要傳入一個執(zhí)行函數(shù)和函數(shù)的參數(shù)脚曾,創(chuàng)建一個Process實例,用start()方法啟動启具。

#### 2. 進程pid
可以通過os模塊的getpid()方法獲取當(dāng)前進程的id本讥,通過getppid()獲取當(dāng)前進程父進程的id。
示例如下:
import multiprocessing,os,time

def run_proc():
    # os.getpid() 取得當(dāng)前進程的id
    # os.getppid() :取得當(dāng)前進程的父進程的id
    while True:
        time.sleep(1)
        print("--run_proc--子進程的父進程的id=%d  子進程的id= %d" % (os.getppid(), os.getpid()))

if  __name__ == "__main__":
    print("--main--主進程的父進程id=%d   主進程的id= %d" % (os.getppid(), os.getpid()))

    # 在主進程中創(chuàng)建一個子進程p1   鲁冯,p1的父進程就是主進程
    p1 = multiprocessing.Process(target=run_proc)
    p1.start()

3. Process語法結(jié)構(gòu)如下:

Process([group [, target [, name [, args [, kwargs]]]]]):

target:如果傳遞了函數(shù)的引用拷沸,可以認(rèn)為這個子進程就執(zhí)行這里的代碼
args:給target指定的函數(shù)傳遞的參數(shù),以元組的方式傳遞
kwargs:給target指定的函數(shù)傳遞命名參數(shù)
name:給進程設(shè)定一個名字晓褪,可以不設(shè)定
group:指定進程組堵漱,大多數(shù)情況下用不到

Process創(chuàng)建的實例對象的常用方法:

start():啟動子進程實例(創(chuàng)建子進程)
is_alive():判斷進程子進程是否還在活著
join([timeout]):是否等待子進程執(zhí)行結(jié)束,或等待多少秒
terminate():不管任務(wù)是否完成涣仿,立即終止子進程
Process創(chuàng)建的實例對象的常用屬性:

name:當(dāng)前進程的別名勤庐,默認(rèn)為Process-N,N為從1開始遞增的整數(shù)
pid:當(dāng)前進程的pid(進程號)

4. 給子進程指定的函數(shù)傳遞參數(shù)

# -*- coding:utf-8 -*-

from multiprocessing import Process
import os,time

def run_proc(name, age, **kwargs):
    for i in range(10):
        print('子進程運行中好港,name= %s,age=%d ,pid=%d...' % (name, age, os.getpid()))
        print(kwargs)
        time.sleep(0.2)

if __name__=='__main__':
    p = Process(target=run_proc, args=('test',18), kwargs={"m":20})
    p.start()
    sleep(1)  # 1秒中之后愉镰,立即結(jié)束子進程
    p.terminate()
    p.join()

運行結(jié)果:

子進程運行中,name= test,age=18 ,pid=45097...
{'m': 20}
子進程運行中钧汹,name= test,age=18 ,pid=45097...
{'m': 20}
子進程運行中丈探,name= test,age=18 ,pid=45097...
{'m': 20}
子進程運行中,name= test,age=18 ,pid=45097...
{'m': 20}
子進程運行中拔莱,name= test,age=18 ,pid=45097...
{'m': 20}

5. 進程間不同享全局變量

# -*- coding:utf-8 -*-

from multiprocessing import Process
import os,time

nums = [11, 22]

def work1():
    """子進程要執(zhí)行的代碼"""
    print("in process1 pid=%d ,nums=%s" % (os.getpid(), nums))
    for i in range(3):
        nums.append(i)
        time.sleep(1)
        print("in process1 pid=%d ,nums=%s" % (os.getpid(), nums))

def work2():
    """子進程要執(zhí)行的代碼"""
    print("in process2 pid=%d ,nums=%s" % (os.getpid(), nums))

if __name__ == '__main__':
    p1 = Process(target=work1)
    p1.start()
    p1.join()#阻塞主進程碗降,即等待p1進程執(zhí)行完畢再執(zhí)行后續(xù)的代碼。

    p2 = Process(target=work2)
    p2.start()

運行結(jié)果:
in process1 pid=11349 ,nums=[11, 22]
in process1 pid=11349 ,nums=[11, 22, 0]
in process1 pid=11349 ,nums=[11, 22, 0, 1]
in process1 pid=11349 ,nums=[11, 22, 0, 1, 2]
in process2 pid=11350 ,nums=[11, 22]

從運行結(jié)果可以看出塘秦,進程間并沒有共享全局變量nums讼渊。

三、進程尊剔、線程對比

1.功能:

進程爪幻,能夠完成多任務(wù),比如運行的QQ再單獨開一個進程接收推送的消息
線程,能夠完成多任務(wù)挨稿,比如運行的QQ開多個線程來發(fā)送消息仇轻、接收文件、視頻聊天等多個任務(wù)

2.定義的不同

進程是操作系統(tǒng)進行資源分配和調(diào)度的一個基本單位.
線程是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.

3.區(qū)別

一個程序至少有一個進程,一個進程至少有一個線程.
線程的劃分尺度小于進程(資源比進程少)奶甘,使得多線程程序的并發(fā)性高篷店。
進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存甩十,從而極大地提高了程序的運行效率
線程不能夠獨立執(zhí)行船庇,必須依存在進程中

4.優(yōu)缺點

線程和進程在使用上各有優(yōu)缺點:線程執(zhí)行開銷小,但不利于資源的管理和保護侣监;而進程正相反。

四臣淤、進程間通信-Queue

Process之間有時需要通信橄霉,操作系統(tǒng)提供了很多機制來實現(xiàn)進程間的通信。
可以使用multiprocessing模塊的Queue實現(xiàn)多進程之間的數(shù)據(jù)傳遞邑蒋,Queue本身是一個消息列隊程序姓蜂,首先用一個小實例來演示一下Queue的工作原理:

#coding=utf-8

from multiprocessing import Queue

q=Queue(3) #初始化一個Queue對象,最多可接收三條put消息
q.put("消息1") 
q.put("消息2")
print(q.full())  #False
q.put("消息3")
print(q.full()) #True

#因為消息列隊已滿下面的try都會拋出異常医吊,第一個try會等待2秒后再拋出異常钱慢,第二個Try會立刻拋出異常
try:
    q.put("消息4",True,2)
except:
    print("消息列隊已滿,現(xiàn)有消息數(shù)量:%s"%q.qsize())

try:
    q.put_nowait("消息4")
except:
    print("消息列隊已滿卿堂,現(xiàn)有消息數(shù)量:%s"%q.qsize())

#推薦的方式束莫,先判斷消息列隊是否已滿,再寫入
if not q.full():
    q.put_nowait("消息4")

#讀取消息時草描,先判斷消息列隊是否為空览绿,再讀取
if not q.empty():
    for i in range(q.qsize()):
        print(q.get_nowait())

運行結(jié)果:
False
True
消息列隊已滿,現(xiàn)有消息數(shù)量:3
消息列隊已滿穗慕,現(xiàn)有消息數(shù)量:3
消息1
消息2
消息3

說明:

初始化Queue()對象時(例如:q=Queue())饿敲,若括號中沒有指定最大可接收的消息數(shù)量,或數(shù)量為負(fù)值逛绵,那么就代表可接受的消息數(shù)量沒有上限(直到內(nèi)存的盡頭)怀各;

Queue.qsize():返回當(dāng)前隊列包含的消息數(shù)量;

Queue.empty():如果隊列為空术浪,返回True瓢对,反之False ;

Queue.full():如果隊列滿了添吗,返回True,反之False沥曹;

Queue.get([block[, timeout]]):獲取隊列中的一條消息,然后將其從列隊中移除,block默認(rèn)值為True妓美;

1)如果block使用默認(rèn)值僵腺,且沒有設(shè)置timeout(單位秒),消息列隊如果為空壶栋,此時程序?qū)⒈蛔枞ㄍT谧x取狀態(tài))辰如,直到從消息列隊讀到消息為止,如果設(shè)置了timeout贵试,則會等待timeout秒琉兜,若還沒讀取到任何消息,則拋出"Queue.Empty"異常毙玻;

2)如果block值為False豌蟋,消息列隊如果為空,則會立刻拋出"Queue.Empty"異常桑滩;

Queue.get_nowait():相當(dāng)Queue.get(False)梧疲;

Queue.put(item,[block[, timeout]]):將item消息寫入隊列,block默認(rèn)值為True运准;

1)如果block使用默認(rèn)值幌氮,且沒有設(shè)置timeout(單位秒),消息列隊如果已經(jīng)沒有空間可寫入胁澳,此時程序?qū)⒈蛔枞ㄍT趯懭霠顟B(tài))该互,直到從消息列隊騰出空間為止,如果設(shè)置了timeout韭畸,則會等待timeout秒宇智,若還沒空間,則拋出"Queue.Full"異常陆盘;

2)如果block值為False普筹,消息列隊如果沒有空間可寫入,則會立刻拋出"Queue.Full"異常隘马;

Queue.put_nowait(item):相當(dāng)Queue.put(item, False)太防;

我們以Queue為例,在父進程中創(chuàng)建兩個子進程酸员,一個往Queue里寫數(shù)據(jù)蜒车,一個從Queue里讀數(shù)據(jù):

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

# 寫數(shù)據(jù)進程執(zhí)行的代碼:
def write(q):
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 讀數(shù)據(jù)進程執(zhí)行的代碼:
def read(q):
    while True:
        if not q.empty():
            value = q.get(True)
            print('Get %s from queue.' % value)
            time.sleep(random.random())
        else:
            break

if __name__=='__main__':
    # 父進程創(chuàng)建Queue,并傳給各個子進程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 啟動子進程pw幔嗦,寫入:
    pw.start()    
    # 等待pw結(jié)束:
    pw.join()
    # 啟動子進程pr酿愧,讀取:
    pr.start()
    pr.join()
    # pr進程里是死循環(huán),無法等待其結(jié)束邀泉,只能強行終止:
    print('')
    print('所有數(shù)據(jù)都寫入并且讀完')

五嬉挡、進程池Pool

當(dāng)需要創(chuàng)建的子進程數(shù)量不多時钝鸽,可以直接利用multiprocessing中的Process動態(tài)生成多個進程,但如果是上百甚至上千個目標(biāo)庞钢,手動的去創(chuàng)建進程的工作量巨大拔恰,此時就可以用到multiprocessing模塊提供的Pool方法。

初始化Pool時基括,可以指定一個最大進程數(shù)颜懊,當(dāng)有新的請求提交到Pool中時,如果池還沒有滿风皿,那么就會創(chuàng)建一個新的進程用來執(zhí)行該請求河爹;但如果池中的進程數(shù)已經(jīng)達(dá)到指定的最大值,那么該請求就會等待桐款,直到池中有進程結(jié)束咸这,才會用之前的進程來執(zhí)行新的任務(wù),請看下面的實例:

# -*- coding:utf-8 -*-

from multiprocessing import Pool
import os, time, random

def worker(msg):
    t_start = time.time()
    print("%s開始執(zhí)行,進程號為%d" % (msg,os.getpid()))
    # random.random()隨機生成0~1之間的浮點數(shù)
    time.sleep(random.random()*2) 
    t_stop = time.time()
    print(msg,"執(zhí)行完畢魔眨,耗時%0.2f" % (t_stop-t_start))

po = Pool(3)  # 定義一個進程池炊苫,最大進程數(shù)3
for i in range(0,10):
    # Pool().apply_async(要調(diào)用的目標(biāo),(傳遞給目標(biāo)的參數(shù)元祖,))
    # 每次循環(huán)將會用空閑出來的子進程去調(diào)用目標(biāo)
    po.apply_async(worker,(i,))

print("----start----")
po.close()  # 關(guān)閉進程池,關(guān)閉后po不再接收新的請求
po.join()  # 等待po中所有子進程執(zhí)行完成冰沙,必須放在close語句之后
print("-----end-----")

運行結(jié)果:
----start----
0開始執(zhí)行,進程號為21466
1開始執(zhí)行,進程號為21468
2開始執(zhí)行,進程號為21467
0 執(zhí)行完畢,耗時1.01
3開始執(zhí)行,進程號為21466
2 執(zhí)行完畢执虹,耗時1.24
4開始執(zhí)行,進程號為21467
3 執(zhí)行完畢拓挥,耗時0.56
5開始執(zhí)行,進程號為21466
1 執(zhí)行完畢,耗時1.68
6開始執(zhí)行,進程號為21468
4 執(zhí)行完畢袋励,耗時0.67
7開始執(zhí)行,進程號為21467
5 執(zhí)行完畢侥啤,耗時0.83
8開始執(zhí)行,進程號為21466
6 執(zhí)行完畢,耗時0.75
9開始執(zhí)行,進程號為21468
7 執(zhí)行完畢茬故,耗時1.03
8 執(zhí)行完畢盖灸,耗時1.05
9 執(zhí)行完畢,耗時1.69
-----end-----

multiprocessing.Pool常用函數(shù)解析:

apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用func(并行執(zhí)行磺芭,堵塞方式必須等待上一個進程退出才能執(zhí)行下一個進程)赁炎,args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)列表钾腺;
close():關(guān)閉Pool徙垫,使其不再接受新的任務(wù);
terminate():不管任務(wù)是否完成放棒,立即終止姻报;
join():主進程阻塞,等待子進程的退出间螟, 必須在close或terminate之后使用吴旋;

進程池中的Queue

如果要使用Pool創(chuàng)建進程损肛,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue()荣瑟,否則會得到一條如下的錯誤信息:

RuntimeError: Queue objects should only be shared between processes through inheritance.

下面的實例演示了進程池中的進程如何通信:

# -*- coding:utf-8 -*-

# 修改import中的Queue為Manager
from multiprocessing import Manager,Pool
import os,time,random

def reader(q):
    print("reader啟動(%s),父進程為(%s)" % (os.getpid(), os.getppid()))
    for i in range(q.qsize()):
        print("reader從Queue獲取到消息:%s" % q.get())

def writer(q):
    print("writer啟動(%s),父進程為(%s)" % (os.getpid(), os.getppid()))
    for i in "itcast":
        q.put(i)

if __name__=="__main__":
    print("(%s) start" % os.getpid())
    q = Manager().Queue()  # 使用Manager中的Queue
    po = Pool()
    po.apply_async(writer, (q,))

    time.sleep(1)  # 先讓上面的任務(wù)向Queue存入數(shù)據(jù)治拿,然后再讓下面的任務(wù)開始從中取數(shù)據(jù)

    po.apply_async(reader, (q,))
    po.close()
    po.join()
    print("(%s) End" % os.getpid())

運行結(jié)果:

(11095) start
writer啟動(11097),父進程為(11095)
reader啟動(11098),父進程為(11095)
reader從Queue獲取到消息:i
reader從Queue獲取到消息:t
reader從Queue獲取到消息:c
reader從Queue獲取到消息:a
reader從Queue獲取到消息:s
reader從Queue獲取到消息:t
(11095) End

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市褂傀,隨后出現(xiàn)的幾起案子忍啤,更是在濱河造成了極大的恐慌,老刑警劉巖仙辟,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件同波,死亡現(xiàn)場離奇詭異,居然都是意外死亡叠国,警方通過查閱死者的電腦和手機未檩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粟焊,“玉大人冤狡,你說我怎么就攤上這事∠钐模” “怎么了悲雳?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長香追。 經(jīng)常有香客問我合瓢,道長,這世上最難降的妖魔是什么透典? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任晴楔,我火速辦了婚禮,結(jié)果婚禮上峭咒,老公的妹妹穿的比我還像新娘税弃。我一直安慰自己,他們只是感情好凑队,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布则果。 她就那樣靜靜地躺著,像睡著了一般顽决。 火紅的嫁衣襯著肌膚如雪短条。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天才菠,我揣著相機與錄音茸时,去河邊找鬼。 笑死赋访,一個胖子當(dāng)著我的面吹牛可都,可吹牛的內(nèi)容都是我干的缓待。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼渠牲,長吁一口氣:“原來是場噩夢啊……” “哼旋炒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起签杈,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤瘫镇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后答姥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铣除,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年鹦付,在試婚紗的時候發(fā)現(xiàn)自己被綠了尚粘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡敲长,死狀恐怖郎嫁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情祈噪,我是刑警寧澤泽铛,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站辑鲤,受9級特大地震影響厚宰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遂填,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澈蝙。 院中可真熱鬧吓坚,春花似錦、人聲如沸灯荧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逗载。三九已至哆窿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厉斟,已是汗流浹背挚躯。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留擦秽,地道東北人码荔。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓漩勤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親缩搅。 傳聞我的和親對象是個殘疾皇子越败,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1.進程 1.1多線程的引入 現(xiàn)實生活中 有很多的場景中的事情是同時進行的,比如開車的時候手和腳共同來駕駛汽車硼瓣,再...
    TENG書閱讀 500評論 0 0
  • 多任務(wù)之進程 什么是進程 進程是CPU資源分配的基本單位,進程包含線程筑累,線程依賴于進程袱蜡。 進程的狀態(tài) 就緒態(tài):運行...
    DragonFangQy閱讀 1,293評論 7 8
  • fork(Unix/Linux/Mac) Unix/Linux操作系統(tǒng)提供了一個fork()系統(tǒng)調(diào)用,它非常特殊慢宗。...
    LeeRich閱讀 452評論 0 0
  • 此時此刻坪蚁,我的心境恐怕只有自己能體會吧。 有時候镜沽,前所未有的孤單敏晤。 我是一個獅子座的女生。平時缅茉,我的身邊總會圍繞著...
    玫瑰花的夢閱讀 188評論 6 4
  • 1嘴脾、from/in/on/at/of/between/by方位? eg. Where is she at? 她...
    西特西閱讀 335評論 0 0