oslo.concurrency是一個爲OpenStack其他項目提供用於管理線程的工具庫,這樣,OpenStack其他項目可以直接調用oslo.concurrency庫利用其鎖機制安全的運行多線程和多進程應用,也可以運行外部進程。本文總結了oslo.concurrency中常用的工具類或方法及其對應的使用方法。
1. lockutils
lockutils模塊封裝了oslo庫的鎖機制,其中,定義了讀寫鎖、信號量以及同步裝飾器方法等。本節分別介紹這些類和方法的實現與使用。
1.1 鎖機制
lockutils中的鎖機制實質上是直接使用了fasteners的實現,所以本節直接介紹fasteners庫中的讀寫鎖和共享內存,即ReaderWriteerLock和InterProcessLock類。
1.1.1 ReaderWriterLock類
ReaderWriterLock類實現了一個讀寫鎖,讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。fasteners通過ReadWriterLock類實現了讀鎖和寫鎖,其在該類中定義了READER和WRITER標識分別表示申請的鎖是讀鎖還是寫鎖。使用該類可以獲得多個讀鎖,但只能存在一個寫鎖。在目前的版本中,該類不能實現從讀寫升級到寫鎖,且寫鎖在加鎖時不能獲取讀鎖;而以後可能會對這些問題進行優化。該類的主要方法如下:
- read_lock():爲當前線程申請一個讀鎖,其只有在沒有爲其他線程分配寫鎖時才能獲取成功;如果另一個線程以及獲取了寫鎖,調用該方法會返回RuntimeError異常。
- write_lock():爲當前線程申請一個寫鎖,其只有在沒有爲其他線程分配讀鎖或寫鎖時才能獲取成功;一旦申請寫鎖成功,將會阻塞申請讀鎖的線程。
- is_reader():判斷當前線程是否申請了讀鎖。
- is_writer():判斷當前線程是否申請了寫鎖,或已申請但尚未獲得寫鎖。
- owner():判斷當前線程是否申請了鎖;如果獲得了鎖是讀鎖還是寫鎖。
1.2.1 InterProcessLock類
1.2 信號量
1.3 同步裝飾器
1.4 外部鎖
2 processutils
processutils模塊定義了一系列系統級的工具類和輔助函數。本小節將介紹processutils庫的相關類或方法。
2.1 進程或線程異常類
processutils模塊中定義了多個進程或線程異常類,如參數不合法異常InvalidArgumentError、不知名參數異常UnknownArgumentError、進程執行異常ProcessExecutionError、日誌記錄異常LogErrors等。
2.2 資源限制類
ProcessLimits類封裝了一個進程對資源的限制,這些限制主要包括以下幾個方面:
- address_space:進程地址空間限制。
- core_file_size:core文件大小限制。
- cpu_time:CPU執行當前進程時間限制。
- data_size:數據大小限制。
- file_size:文件大小限制。
- memory_locked:加鎖的內存大小限制。
- number_files:打開的文件最大數量限制。
- number_processes:進程的最大數量限制。
- resident_set_size:最大駐留集(RSS)大小限制。
- stack_size:棧大小限制。
2.3 進程執行方法
- execute()方法:該方法通過啓動一個子進程提取並執行一個命令。主要參數有:待執行的命令cmd;設置當前目錄的cwd;發送到打開的進程process_input;爲進程設置環境變量的env_variables;代表退出進程的int、bool或list值check_exit_code,默認爲0,只有產生異常纔會設置爲其他值;重試延遲時間delay_on_retry,如果設置爲True,表示馬上進行重試操作;cmd重試次數attempts;run_as_root,該值如果設置爲True,則爲cmd命令加上root_helper指定的前綴;爲命令指定的前綴root_helper;shell表示是否使用shell執行這個命令;執行命令記錄日誌的等級loglevel;監聽錯誤日誌log_errors,是一個LogErrors對象;binary,該值如果爲True,則返回Unicode編碼的stdout後stderr;prlimit表示一個ProcessLimits對象,用於限制執行該cmd的命令的資源用量。
- trycmd()方法:execute()的一個裝飾器,使用這個裝飾器可以更加容易的處理錯誤和異常。返回一個包含命令輸出strdout或stderr字符串的元組。如果err不爲空,則表示執行命令出現異常或錯誤。
- ssh_execute():通過ssh執行命令。
- get_worker_count():獲取默認的worker數量,返回CPU的數量;如果無法確定則返回1.
3 watchdog
- logger:一個記錄日誌的對象。
- action:描述將執行的操作。
- level:表示記錄日誌的等級,默認爲debug。
- after:發送消息之前的持續時間,默認爲5s。
4 使用方法
from oslo_concurrency import lockutils
@synchronized('mylock')
def foo(self, *args):
...
@synchronized('mylock')
def bar(self, *args):
...
爲一個方法添加@syschronized裝飾器,可以保證統一時刻只有一個線程執行這個方法;但是,同時可以有兩個方法共享這個鎖,此時統一時刻要麼只能執行foo方法,要麼只能執行bar方法。(in nova/utils.py)
from oslo_concurrency import lockutils
synchronized = lockutils.synchronized_with_prefix('nova-')
(in nova/foo.py)
from nova import utils
@utils.synchronized('mylock')
def bar(self, *args):
...
如果需要設置一個帶有前綴的同步鎖,可以使用如上的方式進行設置。 FORMAT = '%(asctime)-15s %(message)s'
logging.basicConfig(format=FORMAT)
LOG = logging.getLogger('mylogger')
with watchdog.watch(LOG, "subprocess call", logging.ERROR):
subprocess.call("sleep 10", shell=True)
print "done"
如果設置一個看門狗,則可以使用with語法調用watchdog.watch()方法。