【问题标题】:Python Multiprocessing Semaphore not workingPython多处理信号量不起作用
【发布时间】:2018-10-26 23:42:34
【问题描述】:

我希望我的程序一次打印一行,但它一次打印多行并造成乱码。我似乎无法找出为什么信号量没有阻止多个进程相互打印。

我怎样才能让它尊重信号量?

这是我的代码的简化版本,运行时遇到同样的问题(我在 Windows 上运行 Python 2.7.11(无法更改)):

import multiprocessing

rightofway = multiprocessing.Semaphore(1)

def writenum(number):
    rightofway.acquire()
    print("[+] - " + str(number))
    rightofway.release()
    return

def main():
    starting = 0
    ending = 50

    list = range(starting, ending)

    pool = multiprocessing.Pool(10)
    pool.map(writenum, list)
    return

#Required for Windows multiprocessing
if __name__ == '__main__':
    main()

这是一个乱码输出的例子:

[+] - 0
[+] - 1
[+] - 2
[+] - 3
[+] - 4
[+] - 5
[+] - 6
[+] - 7
[[+] - 8
+] - 10[
+] - 9[+] - 11
[+] - 12

[[+] - 13+] - 14

[[+] - 15+] - 16

[[+] - 18+] - 17

[[+] - 19+] - 20

[[+] - 22+] - 21

[[+] - 23+] - 24

[[+] - 26+] - 25

[[+] - 27+] - 28

[[+] - 30+] - 29

[[+] - 31+] - 32

[[+] - 34+] - 33

[[+] - 35+] - 36

[[+] - 38+] - 37

[[+] - 39+] - 40

[[+] - 42+] - 41

[[+] - 43+] - 44

[[+] - 46+] - 45

[[+] - 47+] - 48

[+] - 49

这是我想要的输出示例(注意我不关心顺序):

[+] - 0
[+] - 1
[+] - 2
[+] - 3
[+] - 4
[+] - 5
[+] - 6
[+] - 7
[+] - 8
[+] - 9
[+] - 10
[+] - 11
[+] - 12
[+] - 13
[+] - 14
[+] - 15
[+] - 16
[+] - 17
[+] - 18
[+] - 19
[+] - 20
[+] - 21
[+] - 22
[+] - 23
[+] - 24
[+] - 25
[+] - 26
[+] - 27
[+] - 28
[+] - 29
[+] - 30
[+] - 31
[+] - 32
[+] - 33
[+] - 36
[+] - 34
[+] - 35
[+] - 37
[+] - 38
[+] - 40
[+] - 39
[+] - 41
[+] - 42
[+] - 44
[+] - 43
[+] - 45
[+] - 46
[+] - 48
[+] - 47
[+] - 49

【问题讨论】:

  • 你在哪个操作系统上?
  • @tdelaney - Windows。我会把它添加到我的问题中。
  • 我手边没有windows,但这个公认的解决方案使用池的初始化程序。这是我对修复的猜测。锁应该适合您或适应信号量stackoverflow.com/questions/28664720/…
  • @tdelaney - 我尝试了它,它导致了完全相同的乱码输出。锁也不起作用。
  • @tdelaney - 代码对你有用吗?

标签: python multithreading multiprocessing semaphore


【解决方案1】:

你的问题类似于this one

来自多处理编程指南。

将资源显式传递给子进程

...最好将对象作为参数传递给子进程的构造函数。

除了使代码(可能)兼容 Windows ...

在 Windows 上,您需要将共享对象传递给 Process 构造函数的参数列表。否则,子进程将获得一个全新的副本,而不是父进程的副本。这就是为什么您会觉得Semaphore 不起作用。这两个进程正在创建自己不同的 Semaphore 对象,而不是共享同一个对象。

要在 Windows 上将 Semaphore 对象传递给 Pool,您需要付出一些努力,但不要太多。由于不能直接将Semaphore对象传递给writenum函数,所以需要依赖Poolinitializer

from multiprocessing import Semaphore, Pool

mutex = None

def initializer(semaphore):
    """This function is run at the Pool startup. 
    Use it to set your Semaphore object in the child process.

    """
    global mutex

    mutex = semaphore

def writenum(args):
    with mutex:
        print "[+] - " + str(number)

def main():
    semaphore = Semaphore()
    pool = Pool(initializer=initializer, initargs=[semaphore])

    numbers = range(50)

    pool.map(writenum, numbers)

编辑:刚刚注意到我写的是Lock 而不是Semaphore。核心推理保持不变。

【讨论】:

  • 成功了!而且我想我明白为什么代码是这样的,但是我问一下以防万一。为什么我们需要在顶部设置 mutex=None ,即使它是在初始化函数中声明的?另外,为什么初始化函数不是 Pool 对象的一部分?
  • 你能更好地解释一下why is the initializer function not a part of the Pool object这个问题的意思吗?
  • 看来 Pool() 是为了接受参数并将它们带入进程的全局空间而构建的。如果是这样,那为什么我必须自己编写该功能的一部分,而不是简单地将(已经是全局的?)信号量传递给进程?
  • Pool 有两种方式将数据传递给子进程。第一个是通过apply/map 函数参数。这要求参数是可腌制的,Semaphores 不是。您只能依靠第二种方式,即使用initializer 函数。由于该函数无法返回值,因此数据持久化的唯一方法是使用全局变量。
【解决方案2】:

为了让事情变得更容易,Following 为我工作。在Win10上测试。 TL;DR - 使用锁而不是信号量

import multiprocessing

rightofway = multiprocessing.Lock()

def writenum(number):

    with rightofway:
        print("[+] - " + str(number))

    return

def main():
    starting = 0
    ending = 50

    list = range(starting, ending)

    pool = multiprocessing.Pool(10)
    pool.map(writenum, list)
    return

#Required for Windows multiprocessing
if __name__ == '__main__':
    main()

【讨论】:

  • 由于某种原因这对我不起作用。同样混乱的结果。
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-04
  • 2019-04-05
  • 1970-01-01
  • 2014-11-13
相关资源
最近更新 更多