順序執行:你吃飯吃到一半,電話來了,你一直到吃完了之後纔去接,這就說明你不支持併發也不支持並行。
併發:你吃飯吃到一半,電話來了,你停了下來接了電話,接完後繼續吃飯,這說明你支持併發。
並行:你吃飯吃到一半,電話來了,你一邊打電話一邊吃飯,這說明你支持並行python
(1)就緒(Ready)狀態git
當進程已分配到除CPU之外的全部必要的資源,只要得到處理機即可當即執行,這時的進程狀態稱爲就緒狀態。github
(2)執行/運行(Running)狀態當進程已得到處理機,其程序正在處理機上執行,此時的進程狀態稱爲執行狀態。併發
(3)阻塞(Blocked)狀態正在執行的進程,因爲等待某個事件發生而沒法執行時,便放棄處理機而處於阻塞狀態。引發進程阻塞的事件可有多種,例如,等待I/O完成、申請緩衝區不能知足、等待信件(信號)等。app
示例dom
from multiprocessing import Process import time def task(name): print('{} is running!'.format(name)) time.sleep(3) print('{} is done!'.format(name)) # Windows開子進程要寫在__name__==__main__下 # 由於開子進程會從新加載父進程的內容 if __name__ == '__main__': # 建立一個Python中的進程對象 p = Process(target=task, args=('t1', )) # p = Process(target=task, kwargs={'name': 't1'}) p.start() # 調用操做系統接口啓動一個進程執行命令 print('--- 主進程 ----')
多進程示例異步
from multiprocessing import Process import time def task(name): print('{} is running!'.format(name)) time.sleep(3) print('{} is done!'.format(name)) if __name__ == '__main__': for i in range(10): p = Process(target=task, args=(i, )) p.start() print('--- 主進程 ----')
繼承方式建立多進程async
import os from multiprocessing import Process class MyProcess(Process): def __init__(self,name): super().__init__() self.name=name def run(self): print(os.getpid()) print('%s 正在和女主播聊天' %self.name) p1=MyProcess('wupeiqi') p2=MyProcess('yuanhao') p3=MyProcess('nezha') p1.start() #start會自動調用run p2.start() # p2.run() p3.start() p1.join() p2.join() p3.join() print('主線程')
p.daemon:默認值爲False,若是設爲True,表明p爲後臺運行的守護進程,當p的父進程終止時,p也隨之終止,而且設定爲True後,p不能建立本身的新進程,必須在p.start()以前設置
p.name:進程的名稱
p.pid:進程的pid
p.exitcode:進程在運行時爲None、若是爲–N,表示被信號N結束(瞭解便可)
p.authkey:進程的身份驗證鍵,
daemon 守護進程示例ide
from multiprocessing import Process import time def foo(): print(123) time.sleep(1) print("end123") def bar(): print(456) time.sleep(3) print("end456") if __name__ == '__main__': p1=Process(target=foo) p2=Process(target=bar) p1.daemon=True p1.start() p2.start() time.sleep(0.1) print("main-------") """ # 主進程結束了,守護進程隨着結束,致使p1 的 end123 沒法打印出來 123 456 main------- end456 """
p.start():啓動進程,並調用該子進程中的p.run()
p.run():進程啓動時運行的方法,正是它去調用target指定的函數,咱們自定義類的類中必定要實現該方法
p.terminate():強制終止進程p,不會進行任何清理操做,若是p建立了子進程,該子進程就成了殭屍進程,使用該方法須要特別當心這種狀況。若是p還保存了一個鎖那麼也將不會被釋放,進而致使死鎖
p.is_alive():若是p仍然運行,返回True
p.join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間,須要強調的是,p.join只能join住start開啓的進程,而不能join住run開啓的進程
join 的示例函數
from multiprocessing import Process import time def task(n): print('這是子進程:{}'.format(n)) time.sleep(n) print('子進程:{}結束了!'.format(n)) if __name__ == '__main__': start_time = time.time() p1 = Process(target=task, args=(1,)) p2 = Process(target=task, args=(2,)) p3 = Process(target=task, args=(3,)) p1.start() p2.start() p3.start() p1.join() p2.join() p3.join() print('我是主進程') print('共耗時:{}'.format(time.time()-start_time)) """ # 未加 join 主進程不等待其餘子進程程序結束便本身先行結束 我是主進程 共耗時:0.021976947784423828 這是子進程:1 這是子進程:2 這是子進程:3 子進程:1結束了! 子進程:2結束了! 子進程:3結束了! """ """ # 加 join 主進程等待其餘子進程程序結束後再結束 這是子進程:1 這是子進程:2 這是子進程:3 子進程:1結束了! 子進程:2結束了! 子進程:3結束了! 我是主進程 共耗時:3.130025625228882 """
洗手間模型演示無鎖致使的問題
from multiprocessing import Process import time import random def task1(): print('這是 task1 任務'.center(30, '-')) print('task1 進了洗手間') time.sleep(random.randint(1, 3)) print('task1 辦事呢...') time.sleep(random.randint(1, 3)) print('task1 走出了洗手間') def task2(): print('這是 task2 任務'.center(30, '-')) print('task2 進了洗手間') time.sleep(random.randint(1, 3)) print('task2 辦事呢...') time.sleep(random.randint(1, 3)) print('task2 走出了洗手間') def task3(): print('這是 task3 任務'.center(30, '-')) print('task3 進了洗手間') time.sleep(random.randint(1, 3)) print('task3 辦事呢...') time.sleep(random.randint(1, 3)) print('task3 走出了洗手間') if __name__ == '__main__': p1 = Process(target=task1) p2 = Process(target=task2) p3 = Process(target=task3) p1.start() p2.start() p3.start() """ # 洗手間只能進一我的,尼瑪大家..... ---------這是 task1 任務---------- task1 進了洗手間 ---------這是 task2 任務---------- task2 進了洗手間 ---------這是 task3 任務---------- task3 進了洗手間 task2 辦事呢... task1 辦事呢... task3 辦事呢... task1 走出了洗手間 task2 走出了洗手間 task3 走出了洗手間 """
加鎖解決示例
from multiprocessing import Process, Lock import time import random # 生成一個互斥鎖 mutex_lock = Lock() def task1(lock): # 鎖門 lock.acquire() print('這是 task1 任務'.center(30, '-')) print('task1 進了洗手間') time.sleep(random.randint(1, 3)) print('task1 辦事呢...') time.sleep(random.randint(1, 3)) print('task1 走出了洗手間') # 釋放鎖 lock.release() def task2(lock): # 鎖門 lock.acquire() print('這是 task2 任務'.center(30, '-')) print('task2 進了洗手間') time.sleep(random.randint(1, 3)) print('task2 辦事呢...') time.sleep(random.randint(1, 3)) print('task2 走出了洗手間') # 釋放鎖 lock.release() def task3(lock): # 鎖門 lock.acquire() print('這是 task3 任務'.center(30, '-')) print('task3 進了洗手間') time.sleep(random.randint(1, 3)) print('task3 辦事呢...') time.sleep(random.randint(1, 3)) print('task3 走出了洗手間') # 釋放鎖 lock.release() if __name__ == '__main__': p1 = Process(target=task1, args=(mutex_lock, )) p2 = Process(target=task2, args=(mutex_lock, )) p3 = Process(target=task3, args=(mutex_lock, )) # 釋放新建進程的信號,具體誰先啓動沒法肯定 p1.start() p2.start() p3.start() """ ---------這是 task2 任務---------- task2 進了洗手間 task2 辦事呢... task2 走出了洗手間 ---------這是 task1 任務---------- task1 進了洗手間 task1 辦事呢... task1 走出了洗手間 ---------這是 task3 任務---------- task3 進了洗手間 task3 辦事呢... task3 走出了洗手間 """
加鎖的弊端
p.apply(func [, args [, kwargs]])
在一個池工做進程中執行func(*args,**kwargs),而後返回結果。 須要強調的是:此操做並不會在全部池工做進程中並執行func函數。 若是要經過不一樣參數併發地執行func函數,必須從不一樣線程調用p.apply()函數或者使用p.apply_async() p.apply_async(func [, args [, kwargs[callback,]]])
在一個池工做進程中執行func(*args,**kwargs),而後返回結果
callback是可調用對象,接收輸入參數。當func的結果變爲可用時, 將傳遞給callback callback禁止執行任何阻塞操做,不然將接收其餘異步操做中的結果。 p.close() 關閉進程池,防止進一步操做 禁止往進程池內在添加任務(須要注意的是必定要寫在close()的上方) p.join() 等待全部工做進程退出。 此方法只能在close()或teminate()以後調用
from multiprocessing import Pool import os,time def task(n): print('[%s] is running'%os.getpid()) time.sleep(2) print('[%s] is done'%os.getpid()) return n**2 if __name__ == '__main__': # print(os.cpu_count()) #查看cpu個數 p = Pool(4) #最大四個進程 for i in range(1,7):#開7個任務 res = p.apply(task,args=(i,)) #同步的,等着一個運行完才執行另外一個 print('本次任務的結束:%s'%res) p.close()#禁止往進程池內在添加任務 p.join() #在等進程池 print('主') apply同步進程池(阻塞)(串行)
並行進程池實例
from multiprocessing import Pool import os,time def walk(n): print('task[%s] running...'%os.getpid()) time.sleep(3) return n**2 if __name__ == '__main__': p = Pool(4) res_obj_l = [] for i in range(10): res = p.apply_async(walk,args=(i,)) # print(res) #打印出來的是對象 res_obj_l.append(res) #那麼如今拿到的是一個列表,怎麼獲得值呢?咱們用個.get方法 p.close() #禁止往進程池裏添加任務 p.join() # print(res_obj_l) print([obj.get() for obj in res_obj_l]) #這樣就獲得了
回調函數何時用?(回調函數在爬蟲中最經常使用)
造數據的很是耗時
處理數據的時候不耗時
帶有回調函數的實例
from multiprocessing import Pool import requests import os import time def get_page(url): print('<%s> is getting [%s]' %(os.getpid(),url)) response = requests.get(url) #獲得地址 time.sleep(2) print('<%s> is done [%s]'%(os.getpid(),url)) return {'url':url,'text':response.text} def parse_page(res): '''解析函數''' print('<%s> parse [%s]'%(os.getpid(),res['url'])) with open('db.txt','a') as f: parse_res = 'url:%s size:%s\n' %(res['url'],len(res['text'])) f.write(parse_res) if __name__ == '__main__': p = Pool(4) urls = [ 'https://www.baidu.com', 'http://www.openstack.org', 'https://www.python.org', 'https://help.github.com/', 'http://www.sina.com.cn/' ] for url in urls: obj = p.apply_async(get_page,args=(url,),callback=parse_page) p.close() p.join() print('主',os.getpid()) #都不用.get()方法了 回調函數(下載網頁的小例子)
無需回調函數的實例
from multiprocessing import Pool import requests import os def get_page(url): print('<%os> get [%s]' %(os.getpid(),url)) response = requests.get(url) #獲得地址 response響應 return {'url':url,'text':response.text} if __name__ == '__main__': p = Pool(4) urls = [ 'https://www.baidu.com', 'http://www.openstack.org', 'https://www.python.org', 'https://help.github.com/', 'http://www.sina.com.cn/' ] obj_l= [] for url in urls: obj = p.apply_async(get_page,args=(url,)) obj_l.append(obj) p.close() p.join() print([obj.get() for obj in obj_l]) 下載網頁小例子(無需回調函數)