3.4.2中的asyncio问题 - 由于某种原因它终止了

时间:2015-03-17 12:21:48

标签: python debugging python-3.x python-asyncio

python的新手,花了很多时间阅读文档和其他代码我似乎无法在Python 3中获得新的asyncio模块。 它一直在没有堆栈跟踪的情况下终止,给我一个线索,应该永远运行,但不会。

我试图模仿的基本流程概念如下:

从端口读取: 开放端口 - >读取数据(可变长度) - >放在队列1上

然后处理数据: 从queue1获取数据 - >条件适用 - >结果放在队列2

然后写入端口: 从queue2获取数据并写入端口

永远从顶部循环

注意:输入端口上的数据是零星的,可变长度的,并且几个块可能会从“序列”中到达。因此我使用asyncio。我理解asyncio将允许块到达的情况,然后是我的app响应之前的另一个 - 即调用get_io_from_port()有助于协同例程的多次执行。这就是为什么我使用队列来确保process_queue()

的非阻塞

到目前为止我的玩具示例代码:

import queue
import asyncio

@asyncio.coroutine
def process_queue(q1, q2):
    tmp = q1.Get()
    if tmp == 'ABCDEF':
        q2.put('12345')
    elif tmp == 'GHIJKL':
        q2.put =('67890')
    else:
        print('There is a data error')

@asyncio.coroutine
def put_io_to_port(writer, q2):

    if not q2.empty():
        try:
                writer.write(q2.get())

        except IOError as e:
            print('OUT Port issue: ', e)

@asyncio.coroutine
def get_io_from_port(reader, q1):

    try:
        data_i = yield from reader.read(1200)
        q1.put(data_i)

    except IOError as e:
        print('IN Port issue: ', e)

def main():

    q1 = queue()
    q2 = queue()

    loop = asyncio.get_event_loop()     # main loop declaration
    reader, writer = yield from asyncio.open_connection('192.168.1.103', 5555)
                # high-level call open streams - read and write

    print('Start')
    tasks = [
        asyncio.async(get_io_from_port(reader,q1)),
        asyncio.async(process_queue(q1, q2)),
        asyncio.async(put_io_to_port(writer, q2)),]  # do these tasks - in this order

    loop.run_forever(tasks)     # loop through on main loop forever
    loop.close()

if __name__ == '__main__':
    main()

另外,作为旁白 - 如何调试此代码 - 即跟踪?可以提出哪些技巧?我正在使用Eclipse和PyDev,但无济于事。

2 个答案:

答案 0 :(得分:5)

你在这里犯了几个错误。首先,您将main视为正常函数,但您已在其中放置yield from调用,这将自动将其转换为生成器。这意味着什么时候

if __name__ == "__main__":
    main()

main实际上并未执行;对main()的调用只会创建一个立即丢弃的生成器对象(因为您没有将它分配给变量)。这就是为什么你很难调试 - main里面的代码都没有执行。您应该将main转换为协程并使用loop.run_until_complete来代替它。

接下来,您尝试使用queue模块,该模块并非设计用于单线程异步程序。一旦你调用queue.get(),它就会阻止你的主线程,这意味着你的asyncio事件循环将被阻止,这意味着你的整个程序将被解锁。您应该使用coroutine-safe asyncio.Queue代替。

put_io_to_port你也有竞争条件。您只是尝试使用q2消费,如果它不为空,但可能put_io_to_port可能在process_queue有机会运行并填充queue之前执行。如果您完全从if not q2.empty()删除了put_io_to_port支票,那么您似乎没问题。

最后,您使用asyncio.async将协程添加到事件循环中,这很好。但是您有一条评论# do these tasks, in this order,但这不是该计划与asyncio.async的行为方式。它只是将所有协同程序添加到事件循环中,它们都将并行运行。如果你真的希望它们按顺序运行,你应该这样做:

yield from get_io_from_port(reader,q1)
yield from process_queue(q1, q2)
yield from put_io_to_port(writer, q2)

但这里真的没有必要。您可以同时运行所有这些并获得正确的行为;如果一个协程在另一个协程之前执行,它将等待它所依赖的协程传递它所需的数据,然后继续执行。

你也有一些拼写错误(q1.Get()q2.put =(...)等。)

所以,把所有这些修复放在一起就可以了:

import queue
import asyncio

@asyncio.coroutine
def process_queue(q1, q2):
    while True:
        tmp = yield from q1.get()
        if tmp == 'ABCDEF':
            yield from q2.put('12345')
        elif tmp == 'GHIJKL':
            yield from q2.put('67890')
        else:
            print('There is a data error')

@asyncio.coroutine
def put_io_to_port(writer, q2):
    while True:
        try:
            data = yield from q2.get()
            writer.write(data)
        except IOError as e:
            print('OUT Port issue: ', e)

@asyncio.coroutine
def get_io_from_port(reader, q1):
    while True:
        try:
            data_i = yield from reader.read(1200)
            yield from q1.put(data_i)
        except IOError as e:
            print('IN Port issue: ', e)

@asyncio.coroutine
def main():
    q1 = asyncio.Queue()
    q2 = asyncio.Queue()

    reader, writer = yield from asyncio.open_connection('192.168.1.103', 5555)
                # high-level call open streams - read and write

    print('Start')
    tasks = [
        asyncio.async(get_io_from_port(reader,q1)),
        asyncio.async(process_queue(q1, q2)),
        asyncio.async(put_io_to_port(writer, q2)),]


if __name__ == '__main__':
    loop = asyncio.get_event_loop()     # main loop declaration
    loop.run_until_complete(main())

答案 1 :(得分:0)

import queue
import asyncio

@asyncio.coroutine
def process_queue(q1, q2):
    while True:
        tmp = yield from q1.get()
        if tmp == 'ABCDEF':
            yield from q2.put('12345')
        elif tmp == 'GHIJKL':
            yield from q2.put('67890')
        else:
            print('There is a data error')

@asyncio.coroutine
def put_io_to_port(writer, q2):
    while True:
        try:
            data = yield from q2.get()
            writer.write(data)
        except IOError as e:
            print('OUT Port issue: ', e)

@asyncio.coroutine
def get_io_from_port(reader, q1):
    while True:
        try:
            data_i = yield from reader.read(1200)
            yield from q1.put(data_i)
        except IOError as e:
            print('IN Port issue: ', e)

@asyncio.coroutine
def main():
    q1 = asyncio.Queue()
    q2 = asyncio.Queue()

    reader, writer = yield from asyncio.open_connection('192.168.1.103', 5555)
                # high-level call open streams - read and write

    print('Start')

    asyncio.async(get_io_from_port(reader,q1))  # changed items so not
    asyncio.async(process_queue(q1, q2))        # in task list otherwise
    asyncio.async(put_io_to_port(writer, q2))   # they are not visible


if __name__ == '__main__':
    loop = asyncio.get_event_loop()     # main loop declaration
    loop.run_until_complete(main())

使用代码内联查找注释以了解问题。