Re: py

作者: sustainer123 (caster)   2024-09-25 15:23:33
※ 引述《sustainer123 (溫水佳樹的兄長大人)》之銘言:
: 進程(process)
: 進程是載入記憶體且將執行的程式
: 打開工作管理員
: 裡面的東西就是進程
: 每個進程會被分配一個獨立id(pid)
: 簡單來講 電腦執行一項任務就是一個進程
: 多進程(mutiprocessing)
: 假設我們需要同時完成多個任務
: 這時候可以使用多進程
: 多進程也就是說主進程外再建立子進程
: 並且把主進程的東西整份copy過去子進程
: unix中 python可以使用fork()建立子進程
: fork()會把主進程的東西複製到子進程
: 並回傳pid到主進程與子進程
: 主進程會拿到子進程的pid
: 子進程會拿到0
: 假設子進程需要主進程的pid
: 可以使用get.ppid()
: windows並沒有fork指令
: 我看文檔 windows只能用spawn
: spawn與fork差別我沒看很懂
: 大致上就fork比較快但比較不安全
: spawn比較慢但比較安全
: 反正windows也用不到spawn以外兩種 先這樣:)))
: 有興趣可以看下面網站
: 總之 我們使用multiprocessing
: 我直接copy py文檔的code:
: from multiprocessing import Process
: import os
: def info(title):
: print(title)
: print('module name:', __name__)
: print('parent process:', os.getppid())
: print('process id:', os.getpid())
: def f(name):
: info('function f')
: print('hello', name)
: if __name__ == '__main__':
: info('main line')
: p = Process(target=f, args=('bob',))
: p.start()
: p.join()
: 輸出:
: main line
: module name: __main__
: parent process: 1280
: process id: 24780
: function f
: module name: __mp_main__
: parent process: 24780
: process id: 3672
: hello bob
: 首先 程式執行主進程
: 之後程式執行子進程
: 這邊使用process這個類完成任務
: target是目標函數 args是傳入目標函數的參數
: p.start()是啟動子進程
: p.join()是等待子進程結束才會往下運行
: 假設一次要設置多個進程
: 我們可以使用pool 一樣使用文檔code:
: from multiprocessing import Pool
: def f(x):
: return x*x
: if __name__ == '__main__':
: with Pool(5) as p:
: print(p.map(f, [1, 2, 3,4,5,6]))
: 這邊我有修改一下 我在list裡面多加幾個元素
: 這程式是pool池開五個進程
: 然後子進程去處理下面的程式
: 我們這邊只開五個進程 但裡面有6個元素
: 所以6必須等到有個進程被釋出 此元素才會被處理
: 一般來說 pool開的大小 == cpu核數
: 等等再寫進程間溝通跟鎖 先這樣
: 參考資料:
: https://stackoverflow.com/questions/64095876/multiprocessing-fork-vs-spawn
: https://docs.python.org/zh-cn/3.12/library/multiprocessing.html
接著講進程間構通
multiprocessing提供兩種方法queue與pipe
doc:
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # 打印 "[42, None, 'hello']"
p.join()
首先創queue 之後創建子進程執行函數f 參數為queue
開始執行子進程 主進程打印q裡面的東西
這邊q.get()會等到queue裡面有東西為止
最後確認子進程結束才繼續父進程
pipe doc:
from multiprocessing import Process, Pipe
def f(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print(parent_conn.recv()) # 打印 "[42, None, 'hello']"
p.join()
程式碼大同小異
queue跟pipe的差別在於:
假設有兩個進程或線程(thread)同時讀或同時寫會出問題
但queue沒差
使用場景可能就pipe適合只有兩個進程的溝通 queue隨便你用
再談一下鎖
有些情況下 我們會希望執行完成進程1再執行進程2
這就需要用上鎖
doc:
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
try:
print('hello world', i)
finally:
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(10):
Process(target=f, args=(lock, num)).start()
l.acquire()是獲取鎖
假設鎖被其他進程拿走
這邊就會卡著
l.release()
釋放鎖 沒這個會整個程式卡死 一定要寫
鎖大致上就長這樣
我稍微改寫一下上面的code 假設沒鎖的情況:
from multiprocessing import Process
def f(i):
print('hello world', i)
if __name__ == '__main__':
for num in range(10):
p = Process(target=f, args=(num,))
p.start()
輸出:
hello world 1
hello world 0
hello world 2
hello world 3
hello world 4
hello world 5
hello world 6
hello world 7
hello world 8
hello world 9
假如沒有鎖 順序可能就會亂掉
多進程大抵這樣
使用場合就cpu密集任務ㄅ
不過要搞cpu密集任務 py這性能 還不如用別的語言寫
老實說 我實戰也還沒用過多進程
作者: JerryChungYC (JerryChung)   2024-09-25 15:31:00
什麼叫同時打印
作者: sustainer123 (caster)   2024-09-25 15:34:00
就正常情況下 會是一排helloworld0-9我是期待會出現 helloworld1helloworld2並排的輸出或者交錯的情況 我是想舉例沒鎖會發生什麼事不過沒寫好 可能要再改一下或用別的例子
作者: JerryChungYC (JerryChung)   2024-09-25 15:43:00
可是print不是內建一個換行符嗎 不會有並排發生吧
作者: sustainer123 (caster)   2024-09-25 15:46:00
對欸 沒想清楚 這邊我再想一下怎麼改

Links booklink

Contact Us: admin [ a t ] ucptt.com