進程間通訊有多種方式,包括信號,管道,消息隊列,信號量,共享內存,socket等
1.共享內存
Python可以通過mmap模塊實現進程之間的共享內存
mmap文件對象既像一個字符串也像一個普通文件對象。像字符串時因為我們可以改變其中的單個字符,如,obj[index] = 'a',同時我們也可以改變一小段的字符,如 obj[2:5]='aaa'。像文件對象是因為在mmap中會有操作標記,我們可以使用seek()方法來改變mmap對象的操作標記
mmap對象通過mmap()方法來構建,Windows系統和Unix系統下,構建方法是不同的。
window的構造方法:
class
mmap.
mmap
(
fileno,
length[, tagname[, access[, offset]]])
linux的構造方法:
class mmap.mmap(fileno, length[, flags[, prot[, access[, offset]]]])
fileno是文件的標號,可以是普通的文件對象的標號,(文件對象通過fileno()方法獲得),也可以是-1,-1代表這個內存是無名的。length參數定義該內存的長度,如果為0,就去fileno對應的文件的最大長度,access是改mmap對象的權限,可以是ACCESS_READ,ACCESS_WRITE ,ACCESS_COPY三個值,
。
linux中,
flags的值可以是MAP_PRIVATE 和MAP_SHARED ,默認是MAP_SHARED ,改參數用來標識改內存是私有的還是共享的
prot的值可以是PROT_READ 和PROT_WRITE,也是用來定義該mmap的權限的
flags+ prot 和access這種權限定義方式只能取一種,否則會報錯
window中
tagname是這個mmap的標記,用來唯一標記這一塊共享內存,作用像fileno
由於有tagname這個參數,所以在windows中,可以通過領fileno為-1,然后自定義一個tagname,例如‘mysharename’,來令多個進程都能共享同一塊內存
但是在linux中,這種方法就不可以用了,只能通過打開一個文件,獲取fileno來實現。
所以在window中,共享內存更加靈活
mmap對象常用的方法:
- mmap. close ( ) 關閉對象
- mmap. find (string[, start[, end]] ) 在共享內存中查找內容,返回匹配內容最小的操作標記
- mmap. flush ([offset, size] ) 把內存的數據保存到硬盤中
- mmap. move (dest, src, count ) 移動操作標記
- mmap. read (num ) 從操作標記開始讀取num個長度的字符
- mmap. read_byte ( ) 讀取二進制數據
- mmap. readline ( ) 讀取一行數據
- mmap. resize (newsize ) 修改mmap的長度
- mmap. rfind (string[, start[, end]] ) 在共享內存中查找內容,返回匹配內容最大的操作標記
- mmap. seek (pos[, whence] ) 移動操作標記
- mmap. size ( ) 返回mmap對象的長度
- mmap. tell ( ) 返回當前操作標記的位置
- mmap. write (string ) 寫入內容.
- mmap. write_byte (byte ) 寫入二進制內容
-
linux構造例子:
share_file='/tmp/mm.txt' f = open(share_file, 'wb') f.write('a' * share_size) f.close() f = open(share_file, 'r+b') mm = mmap.mmap(f.fileno(), 0) f.close()
因為mmap對象的長度不能大於文件的長度,不然會報錯:ValueError: mmap offset is greater than file siz
所以需要以wb的形式,先打開共享的文件,然后寫入需要共享內存的長度的內容,關閉文件后以r+b方式打開文件,然后構造mmap對象。
當然,下次就可以直接用r+b的方式打開文件,然后構造對象了
參考:https://docs.python.org/2/library/mmap.html#module-mmap
2.信號
信號(signal)-- 進程之間通訊的方式。一個進程一旦接收到信號就會打斷原來的程序執行流程來處理信號。
幾個常用信號:
SIGINT 終止進程 中斷進程 (control+c)
SIGTERM 終止進程 軟件終止信號
SIGKILL 終止進程 殺死進程
SIGALRM 鬧鍾信號
相對於共享內存,信號更加偏向於系統層面的,linux系統也是通過信號來管理進程,而且系統也規定了某些進程接到某些信號后的行為。
當然我們可以通過綁定信號處理函數來修改進程收到信號以后的行為
#encoding=utf-8 import os import signal from time import sleep def my_term(a,b): print "收到sigterm信號" signal.signal(signal.SIGTERM,my_term) def my_usr1(a,b): print "收到SIGUSR1信號" signal.signal(signal.SIGUSR1,my_usr1) while 1: print "我是進程id是",os.getpid() sleep(1)
可以通過os.kill(pid,信號)來主動發送信號
3.通過Queue
__author__ = 'lujianxing' import threading from time import sleep def f(q,t): q.put(t) from multiprocessing import Process,Queue if __name__ == '__main__': q=Queue() p = Process(target=f, args=(q,'ljx.sa')) p.start() p.join() p1 = Process(target=f, args=(q,'ljx.elex')) p1.start() p1.join() print q.qsize()
