简体   繁体   English

Python3异步:并行协程意外阻塞

[英]Python3 asyncio: parallel coroutines are unexpectedly blocking

I am trying to get two functions (coroutines) to work in parallel with shared reader, writer streams from a single open network connection like so: 我正在尝试使两个函数(协程)与共享的读取器,写入器流通过单个开放式网络连接并行运行,如下所示:

reader, writer = yield from asyncio.open_connection(
                    host, port, ssl=sc, loop=loop)

once the connection is open I can share it in two while loops as follows: 一旦连接打开,我可以在两个while循环中共享它,如下所示:

@asyncio.coroutine
def rvcr(loop)
    while True:
        data = yield from reader.readline()
        # do something with it

@asyncio.coroutine
def xmtr(loop)
    while True:
        # get some data
        writer.write(data)

Now I want to schedule these to run in a loop but not block each other. 现在,我想安排它们循环运行,但不会互相阻塞。 I have read many examples but asyncio is confusing me for some reason. 我已经阅读了许多示例,但是由于某种原因,asyncio使我感到困惑。

Some examples show 一些例子表明

loop = asyncio.get_event_loop()
asyncio.async(rcvr(loop))
asyncio.async(xmtr(loop))
loop.run_forever()

But the rcvr function blocks and I can't seem to pass reader and writer in correctly. 但是rcvr功能块,我似乎无法正确传递读写器。 I'm thinking this is a no brainer but for some reason I fail. 我认为这是毫无道理的,但是由于某种原因我失败了。

Can anyone please help. 谁能帮忙。

Ok I got it working, here is a complete example, the only thing I really need is to find a way to cleanly shut it down on Ctrl-C. 好的,我可以正常工作了,这是一个完整的示例,我唯一需要做的就是找到一种在Ctrl-C上完全关闭它的方法。 This will work with or without ssl encryption. 无论使用或不使用ssl加密,都可以使用。

    #!/usr/bin/python3
"""
    Openssl certifcate and key pairs can be created with the following command:
        openssl req -x509 -newkey rsa:2048 -keyout selfsigned.key -nodes -out selfsigned.cert -sha256 -days 1000
    Store your cert file in the same location as this file.

for testing ssl server
This is like telnet localhost:12345 but using your cert and key
openssl s_client -connect localhost:12345
"""

import os
import sys
import ssl
import asyncio

# --------------------- User configurable settings ---------------------------------
host = '127.0.0.1'
port = 8088
#sslcert = './mycert.cert'
sslcert = None

# ===================== End of user configurable settings ==========================

@asyncio.coroutine
def conn(loop):
    if sslcert != None and not os.path.isfile(sslcert):
        print("You certificate file {} seems to be missing...".format(sslcert))
        sys.exit()

    if sslcert != None:
        sc = ssl.create_default_context(ssl.Purpose.SERVER_AUTH,
            cafile=sslcert)
    else:
        sc=None

    print("Opening connection to {} on port {}...".format(host, port))
    try:
        reader, writer = yield from asyncio.open_connection(
                host, port, ssl=sc, loop=loop)
        print("Connected...")
    except:
        print("Connection Failed, check your host name or IP address and port...")
        sys.exit()

    return reader,writer


@asyncio.coroutine
def rcvr(r):
    print("Dropping into receive loop...")
    while True:
        rsp = yield from r.readline()
        print(rsp)
        yield from asyncio.sleep(.1)


@asyncio.coroutine
def xmtr(w):
    print("Dropping into transmitter loop...")
    while True:
        yield from asyncio.sleep(0.05)  # need this to yield control back to the loop
        w.write("Some data...\n".encode())
        yield from w.drain()


if __name__ == '__main__':
    try:
        loop = asyncio.get_event_loop()
        reader,writer = loop.run_until_complete(conn(loop))
        tasks = [loop.create_task(rcvr(reader)), loop.create_task(xmtr(writer))]
        wait_tasks = asyncio.wait(tasks)
        loop.run_until_complete(wait_tasks)
    except KeyboardInterrupt:
        print("Quiting...")
    finally:
        loop.close()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM