Python多进程文件写入锁机制详解与常见陷阱

追风的人
追风的人
发布时间:2026-10-14 | 6人浏览过
原创

本文详细解析Python中使用multiprocessing.Lock进行多进程文件写入时的常见误区。通过对比直接传锁、进程池传锁及每次打开文件三种方案,指出进程间内存不共享导致锁失效的问题,并给出在大数据量写入场景下的有效实践与注意事项。

多进程文件写入锁失效问题分析

在多进程并发场景下,若多个进程同时向同一文件执行写入操作且未加锁控制,极易引发数据交错或错乱。

为解决此问题,Python标准库提供了multiprocessing.Lock()用于实现进程间的互斥访问。

初始尝试中,笔者采用了以下代码结构:


import multiprocessing
lock = multiprocessing.Lock()
class MatchProcess(multiprocessing.Process):
  def __init__(self, threadId, mfile, lock):
    multiprocessing.Process.__init__(self)
    self.threadId = threadId
    self.mfile = mfile
    self.lock = lock
  def run(self):
    while True:
       self.lock.acquire()
       try:
         self.mfile.write('111111111111111111' + '\n')
       finally:
         self.lock.release()
 
if __name__ == '__main__':
  mf = open('test.lst', 'w')
  for i in range(15):
    p = MatchProcess(i, mf, lock)
    p.start() 

实际运行结果显示,文件内容依然出现错乱(注:示例中写入的“1111”仅为演示,实际代码逻辑不同)。

分析表明,尽管lock对象作为参数传递给了各个子进程,但由于进程间内存空间相互独立,每个进程持有的实际上是锁的不同副本,因此无法实现跨进程的互斥效果。

进程池与锁机制的兼容性测试

随后尝试使用进程池(Pool)是否可行,具体测试代码如下:


def run(line):
  lock.acquire()
    try:
      mfile.write('111111111111111111' + '\n')
  finally:
    lock.release()
sf = open('test.lst', 'r')
data_lst = list()
for line in sf: 
  line = line.strip()
  data_lst.append(line)
pool = Pool(15)
pool.map_async(run, data_lst) #map_async方法会将data_lst这个可迭代的对象里面的每个元素依次传入run方法来执行
pool.close()
pool.join()
print 'over'

需特别注意以下代码片段:


pool.close()
pool.join()

这两行代码不可或缺,若缺失,主进程执行完毕后可能直接退出,导致尚未完成的子进程被强制终止。

因此,只有当所有子进程执行完毕后,程序才会打印“over”并结束。

然而测试发现,即便使用进程池,锁机制依然未能起到预期的保护作用。

有效解决方案与性能权衡

最终采用的有效方案如下:


def run(line):
  mfile = open('test2.lst', 'a')
  lock.acquire()
  try:
    mfile.write('111111111111111111' + '\n')
  finally:
    lock.release()
 
sf = open('test.lst', 'r')
data_lst = list()
for line in sf: 
  line = line.strip()
  data_lst.append(line)
 
pList = []
for line in line_lst:
  p = multiprocessing.Process(target=run, args=(line, lock))
  p.start()
  pList.append(p)
 
for p in pList:
  p.join()

经实测,该方式下锁机制确实生效。但在处理大量数据写入时,由于频繁加锁解锁,执行速度显著变慢。

此外,一个令人困惑的现象是:若尝试在创建Process对象时,通过args参数将已打开的文件对象传入run方法,数据无法成功写入文件。具体原因尚待进一步探究。

受限于上述问题,只能采用前文提到的“笨办法”,即每次写入时重新打开文件、写入后关闭。这显然并非最优解,若有更优方案,欢迎留言交流。

由此可见,将已打开的文件句柄传入子进程是无效的。可行的替代思路是仅传入文件名,在run方法中每次写入前打开文件,写入完成后立即关闭。

这里存在一个疑问:为何前文提到的第一种方案(文件打开后传入)在特定情况下看似可行,而此处却无效?

以上关于Python多进程锁的使用方法及常见陷阱的分享,旨在为读者提供参考,欢迎指正与讨论。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表