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,但无济于事。
答案 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())
使用代码内联查找注释以了解问题。