【问题标题】:Implementing code to start multiple threads on top of multiple process in python实现代码以在python中的多个进程之上启动多个线程
【发布时间】:2019-12-10 20:51:15
【问题描述】:

扩展我之前提出的关于 python 中多进程之上的多线程的问题

Can I do multithreads on each process of a multiprocess program?

所以我正在尝试实现一个实现这一目标的示例。首先,我生成 2 个进程,每个进程将在其中创建 10 个线程,但这里看起来有些不对劲。我没有实现任何类型的锁或信号量,所以我希望输出会被打乱(如示例 3 所示)。当我运行此代码示例 1 和 2 时以正确的格式打印。例如 2 我什至尝试创建 2 个线程来启动每个进程,以确保它们不是按顺序启动的。 !为什么会这样?我错过了什么,协调发生在哪里?

import multiprocessing, threading, time

def startThreads(n):
    threads = [threading.Thread(target=printer, args=(n, i))  for i in range(10)]
    [t.start() for t in threads]
    [t.join() for t in threads]

def printer(process_num, thread_num):
    time.sleep(1)
    print(f"Process number: {process_num} thread number: {thread_num}")
    print(f"Process number: P thread number: T")

if __name__ == '__main__':

    # Example 1
    pros = [multiprocessing.Process(target=startThreads, args=(p_num, )) for p_num in range(5)]
    [p.start() for p in pros]
    [p.join() for p in pros]
    # Process number: 0 thread number: 0
    # Process number: P thread number: T
    # Process number: 0 thread number: 4
    # Process number: P thread number: T
    # Process number: 0 thread number: 1
    # Process number: P thread number: T
    # Process number: 0 thread number: 2
    # Process number: P thread number: T
    # Process number: 0 thread number: 3
    # Process number: P thread number: T
    # Process number: 1 thread number: 0
    # ...

    # Example 2
    print()
    startThreads(0)
    # Process number: 0 thread number: 1
    # Process number: P thread number: TProcess number: 0 thread number: 0
    # Process number: P thread number: T

    # Process number: 0 thread number: 2Process number: 0 thread number: 4Process number: 0 thread number: 3
    # Process number: P thread number: T

    # Process number: P thread number: T

    # Process number: P thread number: T

请注意示例 2 中的打印行为如何,另一方面,示例始终以正确的格式(安全打印)打印,而在这两种情况下,打印函数都由线程调用,当我删除打印时也会发生同样的事情格式化,而是使用要打印的固定字符串。

As the discussion in this question says 我们需要实现某种安全的打印方法来让每个打印语句都在一个新行中,但示例 1 不是这种情况


import multiprocessing, threading, time

def startThreads():
    threads = [threading.Thread(target=printer)  for i in range(5)]
    [t.start() for t in threads]
    [t.join() for t in threads]

def printer():
    time.sleep(0.05)
    print(f"Process number: P thread number: T")

if __name__ == '__main__':
    p = multiprocessing.Process(target=startThreads)
    p.start()
    p.join()
    print("=====================================")
    startThreads()

    # Process number: P thread number: T
    # Process number: P thread number: T
    # Process number: P thread number: T
    # Process number: P thread number: T
    # Process number: P thread number: T
    # =====================================
    # Process number: P thread number: TProcess number: P thread number: T
    # Process number: P thread number: T

    # Process number: P thread number: TProcess number: P thread number: T
    #

我尝试只使用一个进程,但它仍然可以安全打印,其中每一行都在新行中打印,但是当我明确调用 startThreads 时,它的行为不一样并且不安全打印,是它的行为是这样的?!

【问题讨论】:

  • 您使用的是哪个 python 版本(影响 GIL)?哪个操作系统(影响抢占式调度)?
  • 无论如何,在我的机器(linux mint 19 和 python 3.8.1)上,输出在两种情况下都不同步。如果你总是得到相同的结果,它必须以某种方式依赖于 os/python 版本。

标签: python python-3.x multithreading multiprocessing


【解决方案1】:

使用相同的代码,我得到scrambled 输出:

1:20:21:3, , 0:00:1, 0:71:5, , 1:40:91:1, 1:6, , , 1:0, , 0:5, 0:4, 0:3, 0:6, 1:7, 0:8, 1:9, , 1:8, 
0:0, 0:10:2, , 0:3, 0:4, 0:50:6, 1:0, , 1:1, 0:7, 1:2, 1:3, 0:9, 0:81:5, 1:4, , 1:71:6, , 1:91:8, , 
0:0, 0:1, 0:40:3, 0:2, , 0:60:5, , 0:70:8, , 0:9, 

尝试多次运行它。如果 1 和 2 总是被打乱 - 也许它取决于平台。

所以我希望输出会被打乱

它没有以任何方式同步。顺序是随机的:)

【讨论】:

  • 我觉得我说的不够清楚,我不是在谈论执行的顺序而是我在谈论下面的例子,看看线程如何不等待前一个完成并打印(以下示例不遵循“T:P, T:P”的模式)0:0, 0:1, 0:20:40:3, , , 0:6, 0:5, 0:9, 0:70:8,,,
  • 为什么要等待?线程处于 GIL(全局解释器锁)之下,因此一次只能执行一个字节码,但线程也是抢占式的,因此可以随时中断执行。例如在打印的中间,这不是原子操作。另一方面,进程是真正并行的,因此可能会同时打印 2 个进程。
  • 那么为什么当我独立调用 startThreads 时输出没有格式化,而在我创建的进程中调用它时输出格式正确,你明白我的意思吗?这个实现在我创建的进程之上创建线程是否正确?
  • 这就是重点。这是随机的:P。你的实现是正确的。有关奇怪打印的更多信息,请参阅stackoverflow.com/questions/3029816/…
  • 看起来end 值是单独打印的,如果您将打印更改为print(f"{process_num}:{thread_num}, ", end=''),那么在任何情况下都不会重叠
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-27
  • 2023-02-11
  • 1970-01-01
相关资源
最近更新 更多