我希望在编写日志文件时阅读它们并使用asyncio处理它们的输入。代码必须在Windows上运行。根据我在搜索stackoverflow和web时的理解,异步文件I / O在大多数操作系统上都很棘手(例如,select
将无法正常工作)。虽然我确信我可以用其他方法(例如线程)做到这一点,但我会尝试使用asyncio来查看它是什么样的。最有用的答案可能是描述这个问题的解决方案的“架构”应该是什么样的,即应该如何调用或调度不同的函数和协程。
以下为我提供了一个逐行读取文件的生成器(通过轮询,这是可以接受的):
import time
def line_reader(f):
while True:
line = f.readline()
if not line:
time.sleep(POLL_INTERVAL)
continue
process_line(line)
要监视和处理多个文件,这种代码需要线程。我稍微修改了它以便更适用于asyncio:
import asyncio
def line_reader(f):
while True:
line = f.readline()
if not line:
yield from asyncio.sleep(POLL_INTERVAL)
continue
process_line(line)
当我通过asyncio事件循环安排它时,这种方法有效,但如果process_data
阻塞,那么这当然不好。在开始时,我想象解决方案看起来像
def process_data():
...
while True:
...
line = yield from line_reader()
...
但我无法弄清楚如何做到这一点(至少没有process_data
管理相当多的状态)。
关于如何构建这种代码的任何想法?
答案 0 :(得分:21)
使用aiofiles:
async with aiofiles.open('filename', mode='r') as f:
async for line in f:
print(line)
编辑1
正如@Jashandeep所提到的,你应该关心阻止操作:
另一种方法是select
和/或epoll
:
from select import select
files_to_read, files_to_write, exceptions = select([f1, f2], [f1, f2], [f1, f2], timeout=.1)
此处timeout
参数很重要。
请参阅:https://docs.python.org/3/library/select.html#select.select
编辑2
您可以使用以下命令注册文件以进行读/写:loop.add_reader()
它在循环内部使用内部EPOLL处理程序。
编辑3
但请记住,Epoll不适用于常规文件。
答案 1 :(得分:15)
根据我在搜索stackoverflow和web时的理解,异步文件I / O在大多数操作系统上都很棘手(例如,select不会按预期工作)。虽然我确信我可以用其他方法(例如线程)来做到这一点,但我会尝试使用asyncio来查看它是什么样的。
asyncio
select
基于* nix系统,因此您无法在没有阻止的情况下执行非阻塞文件I / O使用线程。在Windows上,asyncio
可以使用支持非阻止文件I / O的IOCP,但asyncio
不支持此功能。
您的代码很好,除非您应该在线程中阻止I / O调用,这样如果I / O很慢,您就不会阻止事件循环。幸运的是,使用loop.run_in_executor
函数将工作卸载到线程非常简单。
首先,为您的I / O设置专用线程池:
from concurrent.futures import ThreadPoolExecutor
io_pool_exc = ThreadPoolExecutor()
然后只需将任何阻塞I / O调用卸载到执行程序:
...
line = yield from loop.run_in_executor(io_pool_exc, f.readline)
...
答案 2 :(得分:3)
您的代码结构对我来说很好,以下代码在我的机器上正常运行:
import asyncio
PERIOD = 0.5
@asyncio.coroutine
def readline(f):
while True:
data = f.readline()
if data:
return data
yield from asyncio.sleep(PERIOD)
@asyncio.coroutine
def test():
with open('test.txt') as f:
while True:
line = yield from readline(f)
print('Got: {!r}'.format(line))
loop = asyncio.get_event_loop()
loop.run_until_complete(test())
答案 3 :(得分:-1)
asyncio
还不支持文件操作,抱歉。
因此它无法解决您的问题。