第十章 程序和執行緒

2021-07-31 08:06:36 字數 4958 閱讀 1445

對於作業系統來說, 乙個任務就是乙個程序(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...