【问题标题】:Missing lines when writing file with multiprocessing Lock Python使用多处理锁 Python 写入文件时缺少行
【发布时间】:2016-07-28 03:53:22
【问题描述】:

这是我的代码:

from multiprocessing import Pool, Lock
from datetime import datetime as dt

console_out = "/STDOUT/Console.out"
chunksize = 50
lock = Lock()

def writer(message):
    lock.acquire()
    with open(console_out, 'a') as out:
        out.write(message)
        out.flush()
    lock.release()

def conf_wrapper(state):
    import ProcessingModule as procs
    import sqlalchemy as sal

    stcd, nrows = state
    engine = sal.create_engine('postgresql://foo:bar@localhost:5432/schema')

    writer("State {s} started  at: {n}"
           "\n".format(s=str(stcd).zfill(2), n=dt.now()))

    with engine.connect() as conn, conn.begin():
        procs.processor(conn, stcd, nrows, chunksize)

    writer("\tState {s} finished  at: {n}"
           "\n".format(s=str(stcd).zfill(2), n=dt.now()))

def main():
    nprocesses = 12
    maxproc = 1
    state_list = [(2, 113), (10, 119), (15, 84), (50, 112), (44, 110), (11, 37), (33, 197)]

    with open(console_out, 'w') as out:
        out.write("Starting at {n}\n".format(n=dt.now()))
        out.write("Using {p} processes..."
                  "\n".format(p=nprocesses))

    with Pool(processes=int(nprocesses), maxtasksperchild=maxproc) as pool:
        pool.map(func=conf_wrapper, iterable=state_list, chunksize=1)

    with open(console_out, 'a') as out:
        out.write("\nAll done at {n}".format(n=dt.now()))

文件console_out 永远不会包含所有 7 个状态。它总是错过一个或多个状态。这是最新运行的输出:

Starting at 2016-07-27 21:46:58.638587
Using 12 processes...
State 44 started  at: 2016-07-27 21:47:01.482322
State 02 started  at: 2016-07-27 21:47:01.497947
State 11 started  at: 2016-07-27 21:47:01.529198
State 10 started  at: 2016-07-27 21:47:01.497947
    State 11 finished  at: 2016-07-27 21:47:15.701207
    State 15 finished  at: 2016-07-27 21:47:24.123164
    State 44 finished  at: 2016-07-27 21:47:32.029489
    State 50 finished  at: 2016-07-27 21:47:51.203107
    State 10 finished  at: 2016-07-27 21:47:53.046876
    State 33 finished  at: 2016-07-27 21:47:58.156301
    State 02 finished  at: 2016-07-27 21:48:18.856979

All done at 2016-07-27 21:48:18.992277

为什么?

注意,操作系统是 Windows Server 2012 R2。

【问题讨论】:

  • 哪个操作系统?如果您在 Windows 上运行,代码需要更改 lock 才能按预期工作。
  • 视窗。不幸的是。

标签: python python-multiprocessing


【解决方案1】:

由于您在 Windows 上运行,没有任何东西被工作进程继承。每个进程“从头开始”运行整个主程序。

特别是,对于编写的代码,每个进程都有自己的lock 实例,而这些实例彼此无关。简而言之,lock 根本不提供任何进程间互斥。

要解决此问题,可以将 Pool 构造函数更改为调用每进程一次的初始化函数,将Lock() 的实例传递给该函数。比如像这样:

def init(L):
    global lock
    lock = L

然后将这些参数添加到Pool() 构造函数:

initializer=init, initargs=(Lock(),),

你不再需要:

lock = Lock()

行。

那么进程间互斥就会按预期工作。

没有锁

如果您想将所有输出委托给写入器进程,则可以跳过锁定并使用队列来为该进程提供数据 [稍后再查看不同版本]。

def writer_process(q):
    with open(console_out, 'w') as out:
        while True:
            message = q.get()
            if message is None:
                break
            out.write(message)
            out.flush() # can't guess whether you really want this

并将writer() 更改为:

def writer(message):
    q.put(message)

您将再次需要在Pool 构造函数中使用initializer= 和initargs=,以便所有进程都使用相同 队列。

只有一个进程应该运行writer_process(),并且可以作为multiprocessing.Process 的实例自行启动。

最后,让writer_process() 知道是时候退出了, 是时候排空队列并返回了,只需运行

q.put(None)

在主进程中。

稍后

OP 选择了这个版本,因为他们需要同时在其他代码中打开输出文件:

def writer_process(q):
    while True:
        message = q.get()
        if message == 'done':
            break
        else:
            with open(console_out, 'a') as out:
                out.write(message)

我不知道为什么终止哨兵被改为"done"。任何独特的价值都适用于此; None 是传统的。

【讨论】:

  • 然后Pool 在全局命名空间中创建lock,所有工作进程共享,对吗?
  • Nothing 通过魔术在 Windows 上的进程之间共享。 init() 函数在每个进程中调用,后者将每个进程内的进程全局名称lock(由于global lock 语句)绑定到Lock() 的单个实例在主进程中创建并通过主进程。
  • 哦!我得到它。如果不是要求太多,您是否也可以写一个使用 mp.Manager 和 Queue 而不是 Lock 之类的原语的答案?那将是我的首选方法,但是当我尝试时,它根本不起作用。于是我改用Lock,无意中问了这个问题。
  • 我个人会按照所示行使用mp.Queue,但在主进程的线程中运行它(实际上不需要为其创建新进程); t = threading.Thread(target=writer_process, args=(q,)); t.start() 然后当程序结束时 writer(None); t.join()。 mp.Manager 设施可以很方便,但使用它们会产生很高的进程间通信开销,所以我很少发现它们最终“值得”。
  • 不,q.get() 当队列为空时会阻塞,直到将某些内容添加到队列中。阻塞逻辑对 what 被添加到队列是视而不见的——它只是在等待 something 被添加。 None,一个空字符串,一个包含十亿个元素的列表……无所谓。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
  • 2023-01-30
  • 2012-11-06
  • 2013-03-09
  • 2017-08-22
相关资源
最近更新 更多