如何在Python中的传统线程和异步线程之间进行通信?

时间:2019-04-24 12:17:02

标签: python queue message-queue python-asyncio

在python中,在两个threading.Thread之间建立单向通信,将其称为线程a和线程b的惯用方式是什么。

a是生产者,它不断为b生成要消费的值。

b是使用者,它读取a生成的一个值,用协程处理该值,然后读取下一个值,依此类推。

插图:

q = very_magic_queue.Queue()


def worker_of_a(q):
    while True:
        q.put(1)
        time.sleep(1)

a = threading.Thread(worker_of_a, args=(q,))
a.start()


async def loop(q):
    while True:
        # v must be processed in the same order as they are produced
        v = await q.get()
        print(v)

async def foo():
    pass

async def b_main(q):
    loop_fut = asyncio.ensure_future(loop(q))
    foo_fut = asyncio.ensure_future(foo())
    _ = await asyncio.wait([loop_fut, foo_fut], ...)
    # blah blah blah

def worker_of_b(q):
    asyncio.set_event_loop(asyncio.new_event_loop())
    asyncio.get_event_loop().run_until_complete(b_main(q))

b = threading.Thread(worker_of_b, args=(q,))
b.start()

上面的代码当然不起作用,因为queue.Queue.get不能被await设置,并且asyncio.Queue不能在另一个线程中使用。

我还需要一个从ba的沟通渠道。

如果该解决方案也可以与gevent一起使用,那就太好了。

谢谢:)

2 个答案:

答案 0 :(得分:0)

您可以使用queue模块中的同步队列,并将等待时间推迟到ThreadPoolExecutor

ios/2.5.10

答案 1 :(得分:0)

我有一个类似的问题-在线程和异步之间通信数据。我使用的解决方案是创建一个同步队列,并使用asyncio.sleep将异步获取和异步放置的方法添加到非阻塞状态。 这是我的队列类:


#class to provide queue (sync or asyc morph)
class queMorph(queue.Queue):
    def __init__(self,qSize,qNM):
        super().__init__(qSize)
        self.timeout=0.018
        self.me=f'queMorph-{qNM}'
    #Introduce methods for async awaitables morph of Q
    async def aget(self):
        while True:
            try:
                return self.get_nowait()
            except queue.Empty:
                await asyncio.sleep(self.timeout)
            except Exception as E:
                raise
    async def aput(self,data):
        while True:
            try:
                return self.put_nowait(data)
            except queue.Full:
                print(f'{self.me} Queue full on put..')
                await asyncio.sleep(self.timeout)
            except Exception as E:
                raise

要从线程(同步)从队列中放入/获取项目,请使用常规的q.get()和q.put()阻塞函数。 在异步循环中,使用不会阻塞的q.aget()和q.aput()。