前言

GPU.dat的内容如下

81e443bd-b826-4459-999d-685fa63e8a88:/dev/dri/renderD128
166a4eab-fc0d-4264-a35d-8b78e09f22ea:/dev/dri/renderD128
56e846d8-b422-4720-b3e5-c2813b756b9b:/dev/dri/renderD128
2b1a1ecb-357f-4adc-9639-97bf6c8a8e9f:/dev/dri/renderD128
0492e933-0e1f-44c0-b2f3-80f4966bb8ae:/dev/dri/renderD128
b8f4710f-efc1-471b-9055-34fe7261d98b:/dev/dri/renderD128
6214c986-3ba2-420a-a3db-5a1411841de1:/dev/dri/renderD128
c960ee33-f8c2-4255-bbe9-1e971cf4065b:/dev/dri/renderD128
8bb6c888-1f03-4898-b396-4f57ca1571c9:/dev/dri/renderD128
d7afdf91-5ae8-41b9-9610-4a1a73fa3560:/dev/dri/renderD128
55a5a399-aed5-49d3-8fb4-bd16816ba3b2:/dev/dri/renderD128
576bce10-d36a-4a4c-9202-e2a55aa29b89:/dev/dri/renderD128

想要删除指定uuid的某一行,以及多进程调用这个读写文件时怎么实现。

删除某一行

import os

dir = 'test'
gpu_file = os.path.join(dir, 'GPU.dat')
if os.path.exists(gpu_file):
    lines = [l for l in open(gpu_file, "r") if l.find('c960ee33-f8c2-4255-bbe9-1e971cf4065b', 0, 36) != 0]
    fd = open(gpu_file, "w")
    fd.writelines(lines)
    fd.close()

文件锁介绍

GPU.dat相当于一个数据库,添加删除都要做记录,但是当多进程调用时,如一个正打开文件做添加数据操作,另一个进程却要打开文件做删除数据记录,必然会造成文件记录的数据混乱,虽然多进程可以用加锁来解决竞争调用,但是这是从运行的程序来说,而文件锁则要简单的多。

标志位

含义

LOCK_SH

表示要创建一个共享锁,所有进程没有写访问权限,即使是加锁进程也没有。所有进程有读访问权限,在任意时间内,一个文件的共享锁可以被多个进程拥有。

LOCK_EX

表示创建一个排他锁,在任意时间内,一个文件的排他锁只能被一个进程拥有

LOCK_UN

表示删除该进程创建的锁

LOCK_NB

如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。LOCK_NB可以同LOCK_SH或LOCK_NB进行按位或(|)运算操作。 fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)

通常情况下,如果加锁请求不能被立即满足,那么系统调用 flock()会阻塞当前进程。比如,进程想要请求一个排他锁,但此时,已经由其他进程获取了这个锁,那么该进程将会被阻塞。

注意:

  1. 对于文件的 close() 操作会使文件锁失效;
  2. 同理,进程结束后文件锁失效;
  3. flock() 的 LOCK_EX是“劝告锁”,系统内核不会强制检查锁的状态,需要在代码中进行文件操作的地方显式检查才能生效。
import fcntl
import os

dir = 'test'
gpu_file = os.path.join(dir, 'GPU.dat')
if os.path.exists(gpu_file):
    lines = [l for l in open(gpu_file, "r") if l.find('c960ee33-f8c2-4255-bbe9-1e971cf4065b', 0, 36) != 0]
    fd = open(gpu_file, "w")
    fcntl.flock(fd, fcntl.LOCK_EX)
    fd.writelines(lines)
    fcntl.flock(fd, fcntl.LOCK_EX)
    fd.close()

示例

import fcntl
import os
import sys
import threading
import time

dir = 'test'
def writing(name):
    """写操作"""
    gpu_file = os.path.join(dir, 'test.dat')
    if not os.path.exists(gpu_file):
        os.mknod(gpu_file)
    with open(gpu_file, 'a') as f:
        fcntl.flock(f, fcntl.LOCK_EX) #对文件进行加锁
        f.write(name + '\n')
        fcntl.flock(f, fcntl.LOCK_UN) #对文件进行解锁

def deleting(name):
    """删操作"""
    gpu_file = os.path.join(dir, 'test.dat')
    if os.path.exists(gpu_file):
        lines = [l for l in open(gpu_file, "r") if l.find(name, 0, 1) != 0]
        print('lines=%s'%lines)
        fd = open(gpu_file, "w")
        fcntl.flock(fd, fcntl.LOCK_EX)
        fd.writelines(lines)
        fcntl.flock(fd, fcntl.LOCK_UN)
        fd.close()
    else:
        print('文件不存在呢,拜拜了您!')
        sys.exit(1)


if __name__ == '__main__':
    p_d = multiprocessing.Pool(20)
    p_w = multiprocessing.Pool(20)
    a = [chr(i) for i in range(65,91)] #26个大写字母
    for i in a:
        threading.Thread(target=writing, kwargs={'name':i}).start()
    a.remove(a[-1])
    for j in a:
        p_d.apply_async(deleting, j)
        i = '@@' + j
        p_w.apply_async(writing,(i,))
    p_w.close()
    p_w.join()

运行后的结果

Z
@@A
@@U
@@V
@@W
@@X
@@Y
@@B
@@C
@@D
@@E
@@F
@@G
@@H
@@I
@@J
@@K
@@L
@@M
@@N
@@O
@@P
@@Q
@@R
@@S
@@T

如果不加文件锁,文件记录结果可能会发生混乱。
查看官方文档说明可以知道,python中的fcntl是对Unix的fcntl进行封装,并且可以细节到对文件的一部分进行加锁,这部分可以参考python的fcntl官方文档说明。

后言

os.path.exists(gpu_file)
os.path.join(dir, 'test.dat')