Python使用文件鎖實(shí)現(xiàn)進(jìn)程間同步功能【基于fcntl模塊】
本文實(shí)例講述了Python使用文件鎖實(shí)現(xiàn)進(jìn)程間同步功能。分享給大家供大家參考,具體如下:
簡(jiǎn)介
在實(shí)際應(yīng)用中,會(huì)出現(xiàn)這種應(yīng)用場(chǎng)景:希望shell下執(zhí)行的腳本對(duì)某些競(jìng)爭(zhēng)資源提供保護(hù),避免出現(xiàn)沖突。本文將通過(guò)fcntl模塊的文件整體上鎖機(jī)制來(lái)實(shí)現(xiàn)這種進(jìn)程間同步功能。
fcntl系統(tǒng)函數(shù)介紹
Linux系統(tǒng)提供了文件整體上鎖(flock)和更細(xì)粒度的記錄上鎖(fcntl)功能,底層功能均可由fcntl函數(shù)實(shí)現(xiàn)。
首先來(lái)了解記錄上鎖。記錄上鎖是讀寫(xiě)鎖的一種擴(kuò)展類型,它可用于有親緣關(guān)系或無(wú)親緣關(guān)系的進(jìn)程間共享某個(gè)文件的讀與寫(xiě)。被鎖住的文件通過(guò)其描述字訪問(wèn),執(zhí)行上鎖操作的函數(shù)是fcntl。這種類型的鎖在內(nèi)核中維護(hù),其宿主標(biāo)識(shí)為fcntl調(diào)用進(jìn)程的進(jìn)程ID。這意味著這些鎖用于不同進(jìn)程間的上鎖,而不是同一進(jìn)程內(nèi)不同線程間的上鎖。
fcntl記錄上鎖即可用于讀也可用于寫(xiě),對(duì)于文件的任意字節(jié),最多只能存在一種類型的鎖(讀鎖或?qū)戞i)。而且,一個(gè)給定字節(jié)可以有多個(gè)讀寫(xiě)鎖,但只能有一個(gè)寫(xiě)入鎖。
對(duì)于一個(gè)打開(kāi)著某個(gè)文件的給定進(jìn)程來(lái)說(shuō),當(dāng)它關(guān)閉該文件的任何一個(gè)描述字或者終止時(shí),與該文件關(guān)聯(lián)的所有鎖都被刪除。鎖不能通過(guò)fork由子進(jìn)程繼承。
NAME fcntl - manipulate file descriptor SYNOPSIS #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); DESCRIPTION fcntl() performs one of the operations described below on the open file descriptor fd. The operation is determined by cmd. fcntl() can take an optional third argument. Whether or not this argument is required is determined by cmd. The required argument type is indicated in parentheses after each cmd name (in most cases, the required type is int, and we identify the argument using the name arg), or void is specified if the argument is not required. Advisory record locking Linux implements traditional ("process-associated") UNIX record locks, as standardized by POSIX. For a Linux-specific alternative with better semantics, see the discussion of open file description locks below. F_SETLK, F_SETLKW, and F_GETLK are used to acquire, release, and test for the existence of record locks (also known as byte-range, file- segment, or file-region locks). The third argument, lock, is a pointer to a structure that has at least the following fields (in unspecified order). struct flock { ... short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Starting offset for lock */ off_t l_len; /* Number of bytes to lock */ pid_t l_pid; /* PID of process blocking our lock (set by F_GETLK and F_OFD_GETLK) */ ... };
其次,文件上鎖源自Berkeley的Unix實(shí)現(xiàn)支持給整個(gè)文件上鎖或解鎖的文件上鎖(file locking),但沒(méi)有給文件內(nèi)的字節(jié)范圍上鎖或解鎖的能力。
fcntl模塊及基于文件鎖的同步功能。
Python fcntl模塊提供了基于文件描述符的文件和I/O控制功能。它是Unix系統(tǒng)調(diào)用fcntl()和ioctl()的接口。因此,我們可以基于文件鎖來(lái)提供進(jìn)程同步的功能。
import fcntl class Lock(object): def __init__(self, file_name): self.file_name = file_name self.handle = open(file_name, 'w') def lock(self): fcntl.flock(self.handle, fcntl.LOCK_EX) def unlock(self): fcntl.flock(self.handle, fcntl.LOCK_UN) def __del__(self): try: self.handle.close() except: pass
應(yīng)用
我們做一個(gè)簡(jiǎn)單的場(chǎng)景應(yīng)用:需要從指定的服務(wù)器上下載軟件版本到/exports/images目錄下,因?yàn)檫@個(gè)腳本可以在多用戶環(huán)境執(zhí)行。我們不希望下載出現(xiàn)沖突,并僅在該目錄下保留一份指定的軟件版本。下面是基于文件鎖的參考實(shí)現(xiàn):
if __name__ == "__main__": parser = OptionParser() group = OptionGroup(parser, "FTP download tool", "Download build from ftp server") group.add_option("--server", type="string", help="FTP server's IP address") group.add_option("--username", type="string", help="User name") group.add_option("--password", type="string", help="User's password") group.add_option("--buildpath", type="string", help="Build path in the ftp server") group.add_option("--buildname", type="string", help="Build name to be downloaded") parser.add_option_group(group) (options, args) = parser.parse_args() local_dir = "/exports/images" lock_file = "/var/tmp/flock.txt" flock = Lock(lock_file) flock.lock() if os.path.isfile(os.path.join(local_dir, options.buildname)): log.info("build exists, nothing needs to be done") log.info("Download completed") flock.unlock() exit(0) log.info("start to download build " + options.buildname) t = paramiko.Transport((options.server, 22)) t.connect(username=options.username, password=options.password) sftp = paramiko.SFTPClient.from_transport(t) sftp.get(os.path.join(options.buildpath, options.buildname), os.path.join(local_dir, options.buildname)) sftp.close() t.close() log.info("Download completed") flock.unlock()
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python進(jìn)程與線程操作技巧總結(jié)》、《Python Socket編程技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門(mén)與進(jìn)階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
Python實(shí)現(xiàn)自動(dòng)上京東搶手機(jī)
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)自動(dòng)上京東搶手機(jī)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02使用相同的Apache實(shí)例來(lái)運(yùn)行Django和Media文件
這篇文章主要介紹了使用相同的Apache實(shí)例來(lái)運(yùn)行Django和Media文件,Django是最具人氣的Python web開(kāi)發(fā)框架,需要的朋友可以參考下2015-07-07Python算法的時(shí)間復(fù)雜度和空間復(fù)雜度(實(shí)例解析)
算法復(fù)雜度分為時(shí)間復(fù)雜度和空間復(fù)雜度,簡(jiǎn)單而講時(shí)間復(fù)雜度指的是語(yǔ)句執(zhí)行次數(shù),空間復(fù)雜度指的是算法所占的存儲(chǔ)空間,本文通過(guò)代碼給大家介紹Python算法的時(shí)間復(fù)雜度和空間復(fù)雜度問(wèn)題,感興趣的朋友一起看看吧2019-11-11Python解析命令行讀取參數(shù)--argparse模塊使用方法
這篇文章主要介紹了Python解析命令行讀取參數(shù)--argparse模塊使用方法,需要的朋友可以參考下2018-01-01如何將Python代碼轉(zhuǎn)化為可執(zhí)行的程序
在Python中,將代碼轉(zhuǎn)成可以執(zhí)行的程序需要安裝庫(kù)pyinstaller,如果是Windows用戶,打開(kāi)Anaconda?Prompt輸入相對(duì)應(yīng)代碼,下面小編給大家詳細(xì)講解如何將Python代碼轉(zhuǎn)化為可執(zhí)行的程序,感興趣的朋友一起看看吧2024-03-03Python解決Flutter項(xiàng)目簡(jiǎn)體字問(wèn)題的方法
作為面向大陸外市場(chǎng)的應(yīng)用,我們經(jīng)常編寫(xiě)代碼的時(shí)候往往忘記切換繁體字導(dǎo)致上線后出現(xiàn)簡(jiǎn)體字,因?yàn)檠芯肯聵I(yè)內(nèi)相關(guān)插件,看看怎么好解決這個(gè)問(wèn)題,OpenCC 支持語(yǔ)言比較多,所以基于此嘗試了用 Python 去實(shí)現(xiàn),需要的朋友可以參考下2024-07-07python 使用cycle構(gòu)造無(wú)限循環(huán)迭代器
這篇文章主要介紹了python 使用cycle構(gòu)造無(wú)限循環(huán)迭代器的方法,幫助大家更好的理解和學(xué)習(xí)python,感興趣的朋友可以了解下2020-12-12Python使用Traits庫(kù)實(shí)現(xiàn)對(duì)象屬性
Python作為一種動(dòng)態(tài)編程語(yǔ)言,它的變量沒(méi)有類型,這種靈活性給快速開(kāi)發(fā)帶來(lái)很多便利,不過(guò)它也不是沒(méi)有缺點(diǎn),Traits庫(kù)的一個(gè)很重要的目的就是為了解決這些缺點(diǎn)所帶來(lái)的問(wèn)題,trait為Python對(duì)象的屬性增加了類型定義的功能2023-11-11