为什么我在Windows上使用async和await获取NotImplementedError?

时间:2017-06-19 14:38:22

标签: python python-asyncio

我有这段代码:

import os
import time
import asyncio


async def run_command(*args):
    """
    Example from:
        http://asyncio.readthedocs.io/en/latest/subprocess.html
    """
    # Create subprocess
    process = await asyncio.create_subprocess_exec(
        *args,
        # stdout must a pipe to be accessible as process.stdout
        stdout=asyncio.subprocess.PIPE)

    # Wait for the subprocess to finish
    stdout, stderr = await process.communicate()

    # Result
    result = stdout.decode().strip()

    # Return stdout
    return result


def run_asyncio_commands(tasks):
    """Run tasks using asyncio and return results"""
    loop = asyncio.get_event_loop()
    commands = asyncio.gather(*tasks)  # Unpack list using *
    results = loop.run_until_complete(commands)
    loop.close()
    return results


if __name__ == '__main__':

    start = time.time()

    cmds = [
        ['du', '-sh', '/Users/fredrik/Desktop'],
        ['du', '-sh', '/Users/fredrik'],
        ['du', '-sh', '/Users/fredrik/Pictures']
    ]

    tasks = []
    for cmd in cmds:
        tasks.append(run_command(*cmd))
    results = run_asyncio_commands(tasks)
    print(results)

    end = time.time()
    print('Script ran in', str(end - start), 'seconds')

当我在Mac上运行Python 3.6.1中的代码时,我得到了这个:

['780K\t/Users/fredrik/Desktop', '46G\t/Users/fredrik', '52M\t/Users/fredrik/Pictures']
Script ran in 6.405519008636475 seconds

但是当我在Windows上运行相同的脚本(但du命令替换为适用于Windows的东西时),同样使用Python 3.6.1,我得到了这个:

Traceback (most recent call last):
  File "C:\Users\iruser\Desktop\asynciotest.py", line 66, in <module>
    results = run_asyncio_commands(tasks)
  File "C:\Users\iruser\Desktop\asynciotest.py", line 41, in run_asyncio_commands
    results = loop.run_until_complete(commands)
  File "C:\Users\fredrik\condaenvs\dev_py36\lib\asyncio\base_events.py", line 466, in run_until_complete
    return future.result()
  File "C:\Users\iruser\Desktop\asynciotest.py", line 16, in run_command
    stdout=asyncio.subprocess.PIPE)
  File "C:\Users\fredrik\condaenvs\dev_py36\lib\asyncio\subprocess.py", line 225, in create_subprocess_exec
    stderr=stderr, **kwds)
  File "C:\Users\fredrik\condaenvs\dev_py36\lib\asyncio\base_events.py", line 1190, in subprocess_exec
    bufsize, **kwargs)
  File "C:\Users\fredrik\condaenvs\dev_py36\lib\asyncio\coroutines.py", line 210, in coro
    res = func(*args, **kw)
  File "C:\Users\fredrik\condaenvs\dev_py36\lib\asyncio\base_events.py", line 340, in _make_subprocess_transp
ort
    raise NotImplementedError
NotImplementedError

这就是我用Windows替代Unix命令的方法:

cmds = [['C:/Windows/system32/HOSTNAME.EXE']]

Windows版本信息:

Python 3.6.1 | packaged by conda-forge | (default, May 23 2017, 14:21:39) [MSC v.1900 64 bit (AMD64)] on win32
Windows 10 Pro, version 1703, OS build 15063.413

2 个答案:

答案 0 :(得分:10)

以不同方式实现不同的事件循环。其中一些有限制(有时与操作系统相关)。默认情况下,Windows使用SelectorEventLoop,您可以在doc中看到:

  

SelectorEventLoop特定限制:

     
      
  • 使用的SelectSelector仅支持套接字,限制为512个套接字。
  •   
  • add_reader()和add_writer()只接受套接字的文件描述符
  •   
  • 不支持管道(例如:connect_read_pipe(),connect_write_pipe())
  •   
  • 不支持子进程(例如:subprocess_exec(),subprocess_shell())
  •   

要在Windows中运行代码,您可以使用默认的备用事件循环 - ClassName.find_each do |cn| cn.update_column_b cn.save end

替换行:

ProactorEventLoop

用这个:

loop = asyncio.get_event_loop()

您的代码可以使用。

答案 1 :(得分:0)

3.7.0 Python文档在此处处理此问题: https://docs.python.org/3/library/asyncio-platforms.html#asyncio-windows-subprocess

如果您使用的是Windows,请设置事件循环策略-这样您的代码就会起作用。

在启动时,更改unix专用部分:

cmds = [
    ['du', '-sh', '/Users/fredrik/Desktop'],
    ['du', '-sh', '/Users/fredrik'],
    ['du', '-sh', '/Users/fredrik/Pictures']
]

处理Windows和Unix:

if 'win32' in sys.platform:
    # Windows specific event-loop policy & cmd
    asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
    cmds = [['C:/Windows/system32/HOSTNAME.EXE']]
else:
    # Unix default event-loop policy & cmds
    cmds = [
        ['du', '-sh', '/Users/fredrik/Desktop'],
        ['du', '-sh', '/Users/fredrik'],
        ['du', '-sh', '/Users/fredrik/Pictures']
    ]