網絡傳輸進階篇----並發
一、並發是什麽
? 較為通俗的去理解並發這件事情本身,這就要牽扯到計算機的發展。我再這籠統的概括,在網上能夠找到十分詳細的計算機發展史。
? https://blog.csdn.net/zzwu/article/details/77792789——請參見大佬的文章
? 在計算及一開始,工業生產能力並不能實現如今的多核的生產條件,當然也包括 那個時候並沒有相關的理論。所以,在那個時候運行計算機那是相當的麻煩,很多人只能排著隊等著來。這時候,優秀的程序猿就思考著為什麽不能在計算機計算他人的內容的時候,接著運行別人的呢。因此他們就想到了並發——同時運行多個程序在一個處理器上。因為當程序在運行的時候,除開一些較為復雜的計算下,處理器占用較為多之外,很多時候都是進行的文件的讀寫 也就是 I/O 功能,這只占用計算機處理器的一小部分,大多數的部分就只能白白浪費。畢竟,效率就是生產力啊!!
? 引用百度的正規稱呼——“並發,在操作系統中,是指一個時間段中有幾個程序都處於已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行,但任一個時刻點上只有一個程序在處理機上運行。”——應用自百度
二、進程——基本內容
1.什麽是進程
? 正在進行的一個過程或者說一個任務。
2.進程和程序
? 程序是一對代碼,進程則是程序的運行過程。
3.並發和並行
? 並發是看起來是同時進行了,但實際是處理器在多個任務之間的高速來回移動。
? 並行是真正的同時運行,但條件是得有多個CPU。因為一個CPU只能執行一個任務。
?
三、進程——multiprocessing模塊
1.Process類
? **創建進程**
?
Process([group [, target [, name [, args [, kwargs]]]]]),由該類實例化得到的對象,可用來開啟一個子進程
?
強調:
1. 需要使用關鍵字的方式來指定參數
2. args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號
? **參數介紹**
group參數未使用,值始終為None
?
target表示調用對象,即子進程要執行的任務
?
args表示調用對象的位置參數元組,args=(1,2,‘egon‘,)
?
kwargs表示調用對象的字典,kwargs={‘name‘:‘egon‘,‘age‘:18}
?
name為子進程的名稱
? **方法介紹**
p.start():啟動進程,並調用該子進程中的p.run()
p.run():進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法
?
p.terminate():強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵屍進程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那麽也將不會被釋放,進而導致死鎖
p.is_alive():如果p仍然運行,返回True
?
p.join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間。
? **屬性介紹**
p.daemon:默認值為False,如果設為True,代表p為後臺運行的守護進程,當p的父進程終止時,p也隨之終止,並且設定為True後,p不能創建自己的新進程,必須在p.start()之前設置
?
p.name:進程的名稱
?
p.pid:進程的pid
2.Process類的使用
? **windows的Process必須在 if name == ‘main‘:下**
?
? **創建方式一**
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
p1 = Process(target=people, args=("張三", "man",))
p2 = Process(target=people, args=("李四", "man",))
p3 = Process(target=people, args=("狗蛋", "female",))
?
p1.start()
p2.start()
p3.start()
?
print("主要程序")
? **方式二**
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
class People(Process):
def __init__(self, name, sex):
super().__init__()
self.name = name
self.sex = sex
?
def run(self):
print("%s is %s" % (self.name, self.sex))
?
?
if __name__ == ‘__main__‘:
p1 = People("張三", "man")
p2 = People("李四", "man")
p3 = People("狗蛋", "female")
?
p1.start()
p2.start()
p3.start()
?
print("主要程序")
3.joint
? 通過上面的創建,能發現的一個問題就是:在主進程都已經結束完成後,子進程並沒有完成。因為我們看到的代碼只是向處理器發出了一個信號,但是實際上並沒有運行。而主進程並不需要進行進程方面的創建,直接就運行了。
? 那麽,主進程能夠等著子進程運行完成之後,自己再進行嗎?
? 答案顯然是可以的。
? 只需要在主進程之前加上joint()就可以。
? joint就是認為的對主程序進行阻塞,只有joint所對應的子進程運行完成後,主進程才能運行。
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
p1 = Process(target=people, args=("張三", "man",))
p2 = Process(target=people, args=("李四", "man",))
p3 = Process(target=people, args=("狗蛋", "female",))
?
p1.start()
p2.start()
p3.start()
?
p1.join()
p2.join()
p3.join()
?
print("主要程序")
#註意:有多少個對象,就要有對應的join
? **註意:加上joint的進程並不是串行**
? 因為joint阻塞了主進程,但是子進程還是並發的在進行著。和串行一個一個運行還是有著本質的不用的。
? **對象其他屬性或方法**
? **terminal 與 is——alive**
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
p1 = Process(target=people, args=("張三", "man",))
p1.start()
p1.terminate()
print(p1.is_alive())
print("主要程序")
運行後的結果:
True
主要程序
? **name 與 pid**
?
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
p1 = Process(target=people, args=("張三", "man",))
p1.start()
?
print(p1.name, p1.pid)
?
print("主要程序")
運行結果:
Process-1 17072
主要程序
張三 is man
4.守護進程
? 守護進程就是伴隨主進程左右的子進程,在主進程結束之前,自己絕對不會結束的子進程。
? **強調:一、主進程結束就終止;二、守護進程內不能開子進程,否則拋出異常**
?
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
p1 = Process(target=people, args=("張三", "man",))
?
p1.daemon = True
p1.start()
?
print("主進程")
?
# daemon必須要在start上面
5.互斥鎖
? 並發雖然解決了效率的問題,但是也帶來了一個問題就是容易帶來錯亂。
from multiprocessing import Process
import os,time
def work():
print(‘%s is running‘ %os.getpid())
time.sleep(2)
print(‘%s is done‘ %os.getpid())
?
if __name__ == ‘__main__‘:
for i in range(3):
p=Process(target=work)
p.start()
運行結果:
第一次結果
19428 is running
19364 is running
18716 is running
19428 is done
18716 is done
19364 is done
?
?
第二次結果
28012 is running
7920 is running
23080 is running
7920 is done
28012 is done
23080 is done
? 互斥鎖將解決這個問題。
? 互斥鎖就是一個門衛,誰搶到誰先進去,剩下的人在下面等著。
? 雖然保證了質量,但是效率也就不存在了。互斥鎖將本來的並發變成了串行。
from multiprocessing import Process,Lock
import os,time
def work(lock):
lock.acquire() #加鎖
print(‘%s is running‘ %os.getpid())
time.sleep(2)
print(‘%s is done‘ %os.getpid())
lock.release() #釋放鎖
if __name__ == ‘__main__‘:
lock=Lock()
for i in range(3):
p=Process(target=work,args=(lock,))
p.start()
#加上鎖acquire之後一定要在最後release 否則下面的數據根本進不去
? **互斥鎖與joint**
? joint是一個一個的運行,即上一個結束,下一個進去
? 互斥鎖是多個一起去搶,誰搶到誰運行。然後再搶,在運行。如此循環往復。
? 即,join是將一個任務整體串行,而互斥鎖的好處則是可以將一個任務中的某一段代碼串行,比如只讓task函數中的get任務串行
def task(name,):
search(name) # 並發執行
?
lock.acquire()
get(name) #串行執行
lock.release()
? 互斥鎖中可以有部分是並發執行,而joint無法做到
6.隊列
? **重要**
#隊列的創建
Queue([maxsize]):創建共享的進程隊列,Queue是多進程安全的隊列,可以使用Queue實現多進程之間的數據傳遞。
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
import queue
?
?
def people(name, sex):
print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
p1 = Process(target=people, args=("張三", "man",))
p2 = Process(target=people, args=("李四", "man",))
p3 = Process(target=people, args=("狗蛋", "female",))
?
q = queue.Queue(2)
q.put(p1)
q.put(p2)
print(q.full())
?
p1.start()
p2.start()
p3.start()
print(q.get())
print(q.get())
?
print(q.empty())
?
print("主要程序")
#如果q.put()和 q.get()查過2 程序會卡住不再運行
本文知識點引自與http://www.cnblogs.com/linhaifeng/大佬
網絡傳輸進階篇----並發