程序微講解
阿新 • • 發佈:2022-04-19
程序微講解
1.程式碼建立程序
# 建立程序的方式 我們前面已經講過程序就是正在執行的程式碼或者說正在執行的程式,那麼建立程序就有兩種方式。第一種就是當我們用滑鼠 雙擊桌面的一個應用圖示時,就相當於在建立一個程序,我們知道當我們雙擊一個應用圖示就是想要啟動這個程式,雙擊之後就會控 制硬碟轉動,把硬碟中的資料載入到記憶體中,然後CPU再執行記憶體中的任務,其實我們載入到記憶體中的就是程式碼,CPU執行任務其實就 是執行程式碼;第二種就是程式碼建立一個程序,其實還是CPU執行程式碼產生程序。建立程序的本質就是在記憶體空間中申請一塊記憶體空間用 於執行相應的程式程式碼。 # 用程式碼建立程序的第一種方式 from multiprocessing import Process import time def task(name): print(f'{name}剛剛開始') time.sleep(3) print(f'{name}已經結束了') if __name__ == '__main__': p = Process(target=task, args=('oscar',)) # 建立一個程序 p.start() # 告訴作業系統建立一個新的程序 print('主程序') # 用程式碼建立程序的第二種方式 from multiprocessing import Process import time class MyProcess(Process): def __init__(self,name): self.name = name super().__init__() def run(self): print('剛剛來的',self.name) time.sleep(3) print('又走了',self.name) if __name__ == '__main__': p = MyProcess('oscar') p.start() print('主程序') # 不同系統下程式碼建立程序的方式 windows系統:建立程序是以匯入模組的方式進行的,所以建立程序的程式碼必須寫在__main__子程式碼中,否則就會直接報錯,一直在無 限的建立程序。 linux、mac系統:建立程序直接拷貝一份原始碼然後執行即可,不需要寫在__main__子程式碼中。
2.join方法
# 1.join方法的含義及簡單用法 1.join方法可以讓主程序程式碼等待子程序程式碼執行完畢之後在執行。我們在上述建立程序的時候,執行列印的順序是先列印 的主程序的,然後在列印子程序的,我們使用join方法之後就可以先執行子程序的程式碼,子程序的程式碼執行完畢之後在執行主程序的程式碼。 2.簡單用法 from multiprocessing import Process import time def task(name): print(f'{name}剛剛開始') time.sleep(3) print(f'{name}已經結束了') if __name__ == '__main__': p = Process(target=task, args=('oscar',)) # 建立一個程序 p.start() # 告訴作業系統建立一個新的程序 p.join() # 執行完子程序的程式碼之後在執行下面的主程序程式碼 print('主程序') # 2.進一步理解程序的等待過程 from multiprocessing import Process import time def task(name,n): print(f'{name}剛剛來') time.sleep(n) print(f'{name}又走了') if __name__ == '__main__': p1 = Process(target=task,args=('oscar',1)) p2 = Process(target=task,args=('kevin',4)) p3 = Process(target=task,args=('jason',3)) start_time = time.time() p1.start() p2.start() p3.start() p1.join() p2.join() p3.join() end_time = time.time() - start_time print(end_time) # 4.111866235733032 # start_time = time.time() # p1.start() # p1.join() # p2.start() # p2.join() # p3.start() # p3.join() # end_time = time.time() - start_time # print(end_time) # 8.277277231216431 '''當start與join不是交替執行的時候,總耗時就是最長的一個時間,因為當它在等待的時候其他的也在執行,而當start與join 交替執行的時候,總耗時就是所有時間的綜合,因為交替執行的情況下,一個程序在等待,其他的也不會執行,等這一個執行完之後 才會執行下一個'''
3.程序間資料預設隔離
我們知道當我們建立一個程序的時候它是有一個獨自的記憶體空間的,這些記憶體空間是彼此互不干擾的,也就是相互隔離,誰 也不碰誰,預設隔離,但是也是可以通過一些手段打破隔離的,這裡我們先不講,我們先驗證一下程序間的資料是不是預設隔離的。 from multiprocessing import Process s = 1 def task(): global s # 區域性修改全域性不可變型別 s = 2 if __name__ == '__main__': p = Process(target=task) p.start() p.join() # 確保子程序程式碼執行結束在列印s print(s) # 1
4.程序物件屬性和方法
# 檢視程序號
1.在cmd命令列中
Windows:tasklist
mac:ps -ef
2.在pycharm中
(1).current_process函式
from multiprocessing import Process,current_process
print(current_process().pid) # 14320
(2).os模組
from multiprocessing import Process
import os
def task():
print(os.getpid()) # 獲取當前程序的程序號
print(os.getppid()) # 獲取當前程序的父程序號
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join()
# 獲取程序號的用處之一就是可以通過程式碼的方式管理程序
1.殺死子程序
(1).cmd命令列中
windows系統:tsskkill -PID 程序號 -f
mac系統:kill -9 PID
(2).pycharm中
terminate()
2.判斷子程序是否存活
is_alive() # 子程序存活返回True,不存活就返回False
# 通過程式碼管理程序
from multiprocessing import Process
import os
import time
def task():
print(os.getpid())
print(os.getppid())
if __name__ == '__main__':
p = Process(target=task)
p.start() # 建立新的程序需要時間(申請空間、匯入資料)
p.terminate() # 殺死程序也需要時間(銷燬資料、回收空間)
time.sleep(0.1) # 所以我們給主程序加一個等待時間
print(p.is_alive()) # False
print('主程序')
5.殭屍程序與孤兒程序
# 殭屍程序
主程序預設需要等待子程序結束才會結束,所有的子程序在執行結束之後都會變成殭屍程序,意思就是雖然已經執行結
束了,但是還沒有回收,還保留著pid和一些執行過程中的記錄,便於主程序檢視,只是短時間的儲存,然後這些資訊就會被主進
程回收,子程序也就徹底結束了。
結束殭屍程序的兩種方式:
1.主程序正常結束
2.呼叫join方法
# 孤兒程序
子程序存活著,父程序意外死亡,這時候子程序就是孤兒程序,這些孤兒程序就會被作業系統自動接管。
6.守護程序
當一個程序守護另一程序,被守護的程序一旦死亡,那麼守護該程序的程序也就會立刻死亡。
from multiprocessing import Process
import time
def task(name):
print(f'{name}正常活著')
time.sleep(3)
print(f'{name}正常死亡')
if __name__ == '__main__':
p = Process(target=task, args=('tom',))
# 必須寫在start前面
p.daemon = True # 將子程序設定為守護程序:主程序一結束,子程序立馬結束
p.start()
print('主程序死亡') # 只打印了主程序的資訊,然後主程序就結束了,所以子程序立馬死亡,不會執行
7.互斥鎖
在講'互斥鎖'之前我們現講一個現象,過年回家的時候大家一定都搶過車票吧,有時候手機上明明顯示有票,但是點選
購買的時候卻提示沒有票了,然後我們回去檢視車票的時候,發現確實沒有車票了。其實這個現象的原因是這樣的,當我們進入這
個頁面的時候,程式會反饋給我們餘票情況,當我們在檢視餘票的時候,其實其他人已經在購買當中了,所以呢只要你不重新整理或者
不點選下一步,那麼那個頁面的資料是不會改變的,但是隻要你一重新整理,就會重新整理資料,更新為當前的餘票狀況。
# 程式碼模擬搶票
import json
from multiprocessing import Process
import time
import random
# 查票
def search(name):
with open(r'piao.json','r',encoding='utf8') as f:
data = json.load(f)
print('%s查詢當前餘票為:%s'%(name,data['num']))
# 買票
def buy(name):
# 買票之前再次查票,因為期間其他人可能已經把票買走了
with open(r'piao.json', 'r', encoding='utf8') as f:
data = json.load(f)
time.sleep(random.randint(1,3)) # 模仿手機網路延遲
# 判斷是否還有餘票
if data['num'] > 0:
data['num'] -= 1
with open(r'piao.json', 'w', encoding='utf8') as f1:
json.dump(data,f1)
print(f'{name}搶票成功')
else:
print(f'{name}搶票失敗')
def run(name):
search(name)
buy(name)
# 模擬多人同時搶票
if __name__ == '__main__':
for i in range(1,10):
p = Process(target=run,args=(i,))
p.start()
'''上述模擬搶票的程式碼是有問題的,只有一張票每個人都搶到了,這是不符合實際的,所以呢就用到了互斥鎖。'''
# 互斥鎖
當多個程序操作同一份資料的時候會造成資料的錯亂,這個時候就需要加鎖處理(互斥鎖),將併發改為序列,雖然犧
牲了效率但是保證了資料的安全。但是呢互斥鎖並不能輕易使用,容易造成死鎖現象,互斥鎖只在處理資料的部分加鎖,不能什
麼地方都加鎖,否則就嚴重影響到了程式的效率。
所以呢我們就可以對上述程式碼做一下優化,查票可以一次性給所有人看,但是買票的時候必須一個一個來。
# 只需要這兩處優化即可,就可以實現模擬搶票了
from multiprocessing import Process,Lock
def run(name,mutex):
search(name)
# 把買掉環節變成序列
mutex.acquire() # 搶鎖
buy(name)
mutex.release() # 放鎖
# 模擬多人同時搶票
if __name__ == '__main__':
mutex = Lock() # 互斥鎖在主程序中產生一把,交給多個子程序使用
for i in range(1,10):
p = Process(target=run,args=(i,mutex))
p.start()
這裡是IT小白陸祿緋,歡迎各位大佬的指點!!!