對於作業系統來說, 乙個任務就是乙個程序(process)
程序內的這些「子任務」稱為執行緒(thread)
真正的並行執行多工只能在多核cpu上實現
多工的實現有3種方式:
多程序模式;
多執行緒模式;
多程序+多執行緒模式
python既支援多程序, 又支援多執行緒
unix/linux作業系統提供了乙個fork()系統呼叫,它非常特殊。普通的函式呼叫,呼叫一次,返回一次,但是fork()呼叫一次,返回兩次, 因為作業系統自動把當前程序(稱為父程序)複製了乙份(稱為子程序),然後,分別在父程序和子程序內返回。
子程序永遠返回0, 而父程序返回子程序的id, 程序只需要呼叫getppid()就可以拿到父程序的id
在python中可以通過匯入os模組來完成一些系統的呼叫
os.getpid()可以返回當前程序的pid
os.fork()可以呼叫fork系統呼叫, 只不過只是支援linux系列的系統
由於在windows上無法使用fork(), 所以在python中提供了模組multiprocessing來形成子程序
匯入multiprocessing模組的方法是使用from multiprocessing import帶入
利用process函式來建立乙個子程序
第乙個引數可以是用target用於傳遞乙個函式, 用於生成程序之後呼叫該方法
第二個引數是args傳遞的剩餘引數
使用start()方法來啟動子程序
join()方法表示父程序要等待子程序執行完畢之後才能繼續往下執行, 通常用於程序間的同步
具體的使用例項如下
from multiprocessing import process
import os
def run_proc(name):
print('run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print('parent process %s.' % os.getpid())
p = process(target=run_proc, args=('test',))
print('child process will start.')
p.start()
p.join()
print('child process end.')
要建立大量的程序就需要使用程序池
同樣是multiprocessing模組下的, 但是使用的函式是pool
具體是pool()可以傳入乙個值用於設定子程序同時執行的數量, 返回乙個程序池
pool預設的大小是cpu的核心數量
對pool
物件呼叫join()
方法會等待所有子程序執行完畢,呼叫join()
之前必須先呼叫close()
,呼叫close()
之後就不能繼續新增新的process
了
具體建立**
from multiprocessing import pool
import os, time, random
def long_time_task(name):
print('run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__=='__main__':
print('parent process %s.' % os.getpid())
p = pool(4)
for i in range(5):
print('waiting for all subprocesses done...')
p.close()
p.join()
print('all subprocesses done.')
如果不僅要建立執行子程序, 還需要控制程序的輸入和輸出, 那就需要使用subprocess模組
具體**如下
import subprocess
print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])
print('exit code:', r)
程序之間還需要通訊, python通過queue和pipes來交換資料
下面是建立兩個程序, 乙個是往queue裡寫入資料, 乙個是從queue裡讀資料
具體**如下
from multiprocessing import process, queue
import os, time, random
# 寫資料程序執行的**:
def write(q):
print('process to write: %s' % os.getpid())
for value in ['a', 'b', 'c']:
print('put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 讀資料程序執行的**:
def read(q):
print('process to read: %s' % os.getpid())
while true:
value = q.get(true)
print('get %s from queue.' % value)
if __name__=='__main__':
# 父程序建立queue,並傳給各個子程序:
q = queue()
pw = process(target=write, args=(q,))
pr = process(target=read, args=(q,))
# 啟動子程序pw,寫入:
pw.start()
# 啟動子程序pr,讀取:
pr.start()
# 等待pw結束:
pw.join()
# pr程序裡是死迴圈,無法等待其結束,只能強行終止:
pr.terminate()
乙個程序至少有乙個執行緒
執行緒是作業系統直接支援的執行單元
在python中提供兩個模組程序執行緒的操作, 乙個是_thread, 乙個是threading
其中_thread是低階模組, threading是高階模組, 對_thread程序了封裝, 一般只使用threading就行
啟動乙個執行緒就是把乙個函式傳入並建立thread例項, 然後呼叫start()開始執行
由於任何程序預設就會啟動乙個執行緒,我們把該執行緒稱為主線程, 主線程又可以啟動新的執行緒
python的threading模組有個current_thread()函式,它永遠返回當前執行緒的例項
主線程例項的名字叫mainthread,子執行緒的名字在建立時指定,我們用loopthread命名子執行緒
名字僅僅在列印時用來顯示,完全沒有其他意義,如果不起名字python就自動給執行緒命名為thread-1,thread-2……
具體**如下
import time, threading
# 新執行緒執行的**:
def loop():
print('thread %s is running...' % threading.current_thread().name)
n = 0
while n < 5:
n = n + 1
print('thread %s >>> %s' % (threading.current_thread().name, n))
time.sleep(1)
print('thread %s ended.' % threading.current_thread().name)
print('thread %s is running...' % threading.current_thread().name)
t = threading.thread(target=loop, name='loopthread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)
多執行緒和多程序的區別
多程序中, 同乙個變數, 各自有乙份拷貝, 互相不影響
多執行緒中, 所有變數都是有所有執行緒共享, 任何乙個變數都可以被任何乙個執行緒修改, 所以一定要注意同時修改乙個變數的情況
因此可以使用鎖來實現對併發修改的控制
balance = 0
lock = threading.lock()
def run_thread(n):
for i in range(100000):
# 先要獲取鎖:
lock.acquire()
try:
# 放心地改吧:
change_it(n)
finally:
# 改完了一定要釋放鎖:
lock.release()
第十章 程序管理
10.4 ps 監視程序 10.5 top 即時跟蹤程序資訊 10.6 lsof 檢視占用檔案的程序 10.7 kill 向程序傳送訊號 10.8 nice和renice 調整程序的謙讓度 ps aux 顯示所有程序資訊 ps lax 顯示id ppid 和謙讓度ni lsof database.d...
第十章 dubbo執行緒模型
一 netty的執行緒模型 在netty中存在兩種執行緒 boss執行緒和worker執行緒。1 boss執行緒 作用 個數 2 worker執行緒 作用 個數 注意 二 dubbo的事件派發策略和執行緒池 1 dubbo基於netty。有5種派發策略 2 業務執行緒池 cached 快取執行緒池,...
第十章 函式
使用def關鍵字 定義個數可變的位置形參 定義個數可變的關鍵字形參 定義預設值引數 定義個數可變的位置形參 deffun1 args 結果為乙個元組 print args fun1 10,20,30 10,20,30 定義個數可變的關鍵字形參 deffun2 args 結果為乙個字典 print a...