【问题标题】:Unable to run three threads concurrently after performing thread synchronization through semaphore通过信号量进行线程同步后无法同时运行三个线程
【发布时间】:2021-04-28 08:47:59
【问题描述】:

我能够使用信号量值设置为 1 的信号量获得以下多线程代码的顺序输出。但是,现在不是同时运行 3 个进程,而是一次只运行一个线程,这是预期的。有没有一种方法可以同时运行三个线程并获得顺序输出?

from datetime import datetime
import getpass
import os
import sys
import time
import re
import json
from random import random
import threading
from io import StringIO
from time import gmtime, strftime
from pprint import pprint
from threading import *
screen_lock = Semaphore(value=1)

#------------------------------------------------------------------------------
def config_worker(port):
    if port == 'a':
       screen_lock.acquire()
       print('PASS : Tunnel1 is UP from  router 1')
       print('PASS : Tunnel2 is UP from  router 1')
       print('PASS : Tunnel3 is UP from  router 1')
       screen_lock.release()
       
    if port == 'b':
       screen_lock.acquire()
       print('PASS : Tunnel1 is UP from  router 2')
       print('PASS : Tunnel2 is UP from  router 2')
       print('PASS : Tunnel3 is UP from  router 2')
       screen_lock.release()
       
    if port == 'c':
       screen_lock.acquire()
       print('PASS : Tunnel1 is UP from  router 3')
       print('PASS : Tunnel2 is UP from  router 3')
       print('PASS : Tunnel3 is UP from  router 3')
       screen_lock.release()
    return

def connect():

    config_threads_list = []
    devices = ['a','b','c']
    for ports in devices:
        port = ports
        print ('Creating thread for: ', ports)
        config_threads_list.append(threading.Thread(target=config_worker, args=(port)))

    print ('\n---- Begin get config threading ----\n')
    for config_thread in config_threads_list:
        config_thread.start()

    for config_thread in config_threads_list:
        config_thread.join()



connect()
 

使用信号量输出。输出是正确的,但一次只有一个线程在运行,这是预期的。如何运行所有线程并打印顺序输出?

---- Begin get config threading ----

PASS : Tunnel1 is UP from  router 1
PASS : Tunnel2 is UP from  router 1
PASS : Tunnel3 is UP from  router 1
PASS : Tunnel1 is UP from  router 2
PASS : Tunnel2 is UP from  router 2
PASS : Tunnel3 is UP from  router 2
PASS : Tunnel1 is UP from  router 3
PASS : Tunnel2 is UP from  router 3
PASS : Tunnel3 is UP from  router 3

【问题讨论】:

  • 各位,任何建议都会有所帮助。如果可以的话,请告诉我同样的情况
  • 线程实际上并没有在同时的意义上“并发”运行 - 基本上线程只有在有原因时才会切换 - 通常基于 i/o,但我相信可以使用例如time.sleep(0) 让线程让出,如果有一个线程可以运行,Python 会运行另一个线程。如果您删除锁定并在每个打印语句后添加time.sleep(0),您可能会看到这种情况发生。但是以控制线程切换为目标是矛盾的——如果你认为你需要完全控制线程执行的顺序,那么你可能不应该使用线程,写顺序。
  • 更正 - 不要使用 0,使用例如time.sleep(0.0001’)stackoverflow.com/questions/787803/…
  • hi barny 还有什么好主意

标签: python multithreading


【解决方案1】:

很可能GIL 锁定是问题所在。试试multiprocessing.pool

from multiprocessing import Pool

def connect():
    po = Pool(3)
    res = po.map(config_worker, devices)

【讨论】:

  • 不要相信存在“问题”,这只是 Python 线程的工作方式。
  • 嗨,抱歉,多处理导致我的 windows pc 挂起,你有更好的解决方案吗,添加代码后我无法收到任何输出
  • 在 Windows 上,该代码几乎不可避免地会锁定您 - 您需要使用 if __name__=='__main__': 保护要作为“主”线程执行的代码,请参阅文档 docs.python.org/3/library/multiprocessing.html,所有示例都使用它。多处理与线程完全不同。
【解决方案2】:

正在运行所有线程 - 您可以看出这一点,因为所有输出都已生成。

由于信号量,您总是会得到三个一组的语句。

如果您想要更随机的序列,请尝试添加睡眠(我还添加了打印以显示正在启动的端口线程):

from datetime import datetime
import getpass
import os
import sys
import time
import re
import json
from random import random
import threading
from io import StringIO
from time import gmtime, strftime
from pprint import pprint
from threading import *
screen_lock = Semaphore(value=1)

#------------------------------------------------------------------------------
def config_worker(port):
    print( f"Starting thread {port}" )   # ADDED
    time.sleep(0.0001)                   # ADDED
    if port == 'a':
       screen_lock.acquire()
       print('PASS : Tunnel1 is UP from  router 1')
       print('PASS : Tunnel2 is UP from  router 1')
       print('PASS : Tunnel3 is UP from  router 1')
       screen_lock.release()
       
    if port == 'b':
       screen_lock.acquire()
       print('PASS : Tunnel1 is UP from  router 2')
       print('PASS : Tunnel2 is UP from  router 2')
       print('PASS : Tunnel3 is UP from  router 2')
       screen_lock.release()
       
    if port == 'c':
       screen_lock.acquire()
       print('PASS : Tunnel1 is UP from  router 3')
       print('PASS : Tunnel2 is UP from  router 3')
       print('PASS : Tunnel3 is UP from  router 3')
       screen_lock.release()
    return

def connect():

    config_threads_list = []
    devices = ['a','b','c']
    for ports in devices:
        port = ports
        print ('Creating thread for: ', ports)
        config_threads_list.append(threading.Thread(target=config_worker, args=(port)))

    print ('\n---- Begin get config threading ----\n')
    for config_thread in config_threads_list:
        config_thread.start()

    for config_thread in config_threads_list:
        config_thread.join()



connect()

现在当你运行这段代码时,你可以得到不同的序列,多试几次:

首次运行:

Creating thread for:  a
Creating thread for:  b
Creating thread for:  c

---- Begin get config threading ----

Starting thread a
Starting thread b
Starting thread c
PASS : Tunnel1 is UP from  router 3
PASS : Tunnel2 is UP from  router 3
PASS : Tunnel3 is UP from  router 3
PASS : Tunnel1 is UP from  router 1
PASS : Tunnel2 is UP from  router 1
PASS : Tunnel3 is UP from  router 1
PASS : Tunnel1 is UP from  router 2
PASS : Tunnel2 is UP from  router 2
PASS : Tunnel3 is UP from  router 2

第二次运行:

Creating thread for:  a
Creating thread for:  b
Creating thread for:  c

---- Begin get config threading ----

Starting thread a
Starting thread b
Starting thread c
PASS : Tunnel1 is UP from  router 2
PASS : Tunnel2 is UP from  router 2
PASS : Tunnel3 is UP from  router 2
PASS : Tunnel1 is UP from  router 1
PASS : Tunnel2 is UP from  router 1
PASS : Tunnel3 is UP from  router 1
PASS : Tunnel1 is UP from  router 3
PASS : Tunnel2 is UP from  router 3
PASS : Tunnel3 is UP from  router 3

或者,如果您注释掉 screen_lock.acquire()/screen_lock.release() 行,那么您会得到一个更加混乱的序列(在这种情况下,我将 sleep(0.0001) 保留在其中,但序列在没有睡眠的情况下也会发生变化,大概是因为线程打开打印的 I/O):

Creating thread for:  a
Creating thread for:  b
Creating thread for:  c

---- Begin get config threading ----

Starting thread a
Starting thread b
Starting thread c
PASS : Tunnel1 is UP from  router 3
PASS : Tunnel1 is UP from  router 1
PASS : Tunnel2 is UP from  router 3
PASS : Tunnel2 is UP from  router 1
PASS : Tunnel3 is UP from  router 3
PASS : Tunnel3 is UP from  router 1
PASS : Tunnel1 is UP from  router 2
PASS : Tunnel2 is UP from  router 2
PASS : Tunnel3 is UP from  router 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 2014-11-27
    • 2015-07-06
    相关资源
    最近更新 更多