【问题标题】:Semaphores on PythonPython 上的信号量
【发布时间】:2015-10-09 02:35:35
【问题描述】:

几周前我开始使用 Python 进行编程,并尝试使用 Semaphores 同步两个简单线程,以用于学习目的。这是我所拥有的:

import threading
sem = threading.Semaphore()

def fun1():
    while True:
        sem.acquire()
        print(1)
        sem.release()

def fun2():
    while True:
        sem.acquire()
        print(2)
        sem.release()

t = threading.Thread(target = fun1)
t.start()
t2 = threading.Thread(target = fun2)
t2.start()

但它一直只打印 1。如何插入打印件?

【问题讨论】:

    标签: python multithreading semaphore python-multithreading


    【解决方案1】:

    它工作正常,只是它的打印速度太快,你看不到。尝试在两个函数(少量)中添加 time.sleep() 以使线程休眠这么长的时间,以便实际上能够同时看到 1 和 2。

    例子-

    import threading
    import time
    sem = threading.Semaphore()
    
    def fun1():
        while True:
            sem.acquire()
            print(1)
            sem.release()
            time.sleep(0.25)
    
    def fun2():
        while True:
            sem.acquire()
            print(2)
            sem.release()
            time.sleep(0.25)
    
    t = threading.Thread(target = fun1)
    t.start()
    t2 = threading.Thread(target = fun2)
    t2.start()
    

    【讨论】:

    • 感谢帮助,但我发现了真正的问题,因为我在两个线程中使用相同的信号量,第一个信号量几乎立即完成,因此第二个无法获得锁并执行。
    • @VictorTurrisi 而不是while True 如果你放一个很大的范围并运行你的程序,然后将输出重定向到一个文件然后检查文件,你可能会看到2确实会在两者之间打印,但就像很多 1,然后是很多 2,然后又是很多 1,等等。这是因为它执行得太快,您需要在它们之间放置一个 time.sleep() 以查看它们之后执行一个另一个。
    【解决方案2】:

    我使用此代码演示了如何 1 个线程可以使用信号量,而另一个线程将等待(非阻塞)直到信号量可用。

    这是使用 Python3.6 编写的;未在任何其他版本上测试。

    这只有在从同一个线程进行同步时才有效,使用这种机制来自不同进程的 IPC 将失败。

    import threading
    from  time import sleep
    sem = threading.Semaphore()
    
    def fun1():
        print("fun1 starting")
        sem.acquire()
        for loop in range(1,5):
            print("Fun1 Working {}".format(loop))
            sleep(1)
        sem.release()
        print("fun1 finished")
    
    
    
    def fun2():
        print("fun2 starting")
        while not sem.acquire(blocking=False):
            print("Fun2 No Semaphore available")
            sleep(1)
        else:
            print("Got Semphore")
            for loop in range(1, 5):
                print("Fun2 Working {}".format(loop))
                sleep(1)
        sem.release()
    
    t1 = threading.Thread(target = fun1)
    t2 = threading.Thread(target = fun2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("All Threads done Exiting")
    

    当我运行它时 - 我得到以下输出。

    fun1 starting
    Fun1 Working 1
    fun2 starting
    Fun2 No Semaphore available
    Fun1 Working 2
    Fun2 No Semaphore available
    Fun1 Working 3
    Fun2 No Semaphore available
    Fun1 Working 4
    Fun2 No Semaphore available
    fun1 finished
    Got Semphore
    Fun2 Working 1
    Fun2 Working 2
    Fun2 Working 3
    Fun2 Working 4
    All Threads done Exiting
    

    【讨论】:

      【解决方案3】:

      另外,您可以使用 Lock/mutex 方法如下:

      import threading
      import time
      
      mutex = threading.Lock()  # is equal to threading.Semaphore(1)
      
      def fun1():
          while True:
              mutex.acquire()
              print(1)
              mutex.release()
              time.sleep(.5)
      
      def fun2():
          while True:
              mutex.acquire()
              print(2)
              mutex.release()
              time.sleep(.5)
      
      t1 = threading.Thread(target=fun1).start()
      t2 = threading.Thread(target=fun2).start()
      

      使用“with”的更简单的样式:

      import threading
      import time
      
      mutex = threading.Lock()  # is equal to threading.Semaphore(1)
      
      def fun1():
          while True:
              with mutex:
                  print(1)
              time.sleep(.5)
      
      def fun2():
          while True:
              with mutex:
                  print(2)
              time.sleep(.5)
      
      t1 = threading.Thread(target=fun1).start()
      t2 = threading.Thread(target=fun2).start()
      

      [注意]:

      The difference between mutex, semaphore, and lock

      【讨论】:

        【解决方案4】:

        其实我是想找asyncio.Semaphores,不是threading.Semaphore, 我相信有人可能也想要它。

        所以,我决定分享 asyncio。Semaphores,希望你不要介意。

        from asyncio import (
            Task,
            Semaphore,
        )
        import asyncio
        from typing import List
        
        
        async def shopping(sem: Semaphore):
            while True:
                async with sem:
                    print(shopping.__name__)
                await asyncio.sleep(0.25)  # Transfer control to the loop, and it will assign another job (is idle) to run.
        
        
        async def coding(sem: Semaphore):
            while True:
                async with sem:
                    print(coding.__name__)
                await asyncio.sleep(0.25)
        
        
        async def main():
            sem = Semaphore(value=1)
            list_task: List[Task] = [asyncio.create_task(_coroutine(sem)) for _coroutine in (shopping, coding)]
            """ 
            # Normally, we will wait until all the task has done, but that is impossible in your case.
            for task in list_task:
                await task
            """
            await asyncio.sleep(2)  # So, I let the main loop wait for 2 seconds, then close the program.
        
        
        asyncio.run(main())
        

        输出

        shopping
        coding
        shopping
        coding
        shopping
        coding
        shopping
        coding
        shopping
        coding
        shopping
        coding
        shopping
        coding
        shopping
        coding
        

        16*0.25 = 2

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-12-17
          • 1970-01-01
          • 2011-12-30
          • 2011-02-17
          • 1970-01-01
          • 1970-01-01
          • 2017-03-26
          • 1970-01-01
          相关资源
          最近更新 更多