面试题答案
一键面试'x' 模式的特殊用途
在Python中,文件模式 'x'
代表排他性创建。它用于创建一个新文件,如果文件已存在,则会引发 FileExistsError
异常。这确保了文件创建操作的原子性,因为在同一时刻只有一个进程或线程能够成功创建文件。
多进程并发创建文件场景下的问题
在多进程并发创建文件的场景中,虽然 'x'
模式提供了原子性创建,但如果多个进程同时尝试创建同一个文件,除了一个进程外,其他进程都会因 FileExistsError
异常而失败。这可能导致大量不必要的异常处理开销,影响效率。
设计机制避免问题
为了既保证原子性又提高效率,可以使用操作系统提供的文件锁机制。在Python中,可以使用 fcntl
模块(仅适用于Unix系统)或 msvcrt
模块(适用于Windows系统)来实现文件锁。以下以Unix系统为例,使用 fcntl
模块实现:
-
设计思路:
- 每个进程在尝试创建文件前,先获取文件锁。
- 只有获取到锁的进程才能创建文件,其他进程等待。
- 文件创建完成后,释放锁,允许其他进程尝试获取锁并创建文件。
-
代码示例:
import os
import fcntl
def create_file_atomically(file_path):
lock_file = open(file_path + '.lock', 'w')
try:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
try:
with open(file_path, 'x') as new_file:
pass
print(f"文件 {file_path} 创建成功")
except FileExistsError:
print(f"文件 {file_path} 已存在")
finally:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
lock_file.close()
os.remove(file_path + '.lock')
if __name__ == '__main__':
import multiprocessing
file_path = 'test.txt'
processes = []
for _ in range(5):
p = multiprocessing.Process(target=create_file_atomically, args=(file_path,))
processes.append(p)
p.start()
for p in processes:
p.join()
在上述代码中:
create_file_atomically
函数实现了原子性创建文件的逻辑。- 首先打开一个锁文件
file_path + '.lock'
。 - 使用
fcntl.flock
获取排他锁(fcntl.LOCK_EX
)。 - 尝试以
'x'
模式创建目标文件,如果文件已存在,捕获FileExistsError
异常。 - 最后释放锁并删除锁文件。
在 if __name__ == '__main__':
块中,启动多个进程并发调用 create_file_atomically
函数,模拟多进程并发创建文件的场景。这样既保证了文件创建的原子性,又避免了因频繁异常导致的效率问题。
对于Windows系统,可以使用 msvcrt.locking
函数实现类似的文件锁机制,原理类似,但函数调用和参数略有不同。