【问题标题】:RuntimeWarning: coroutine was never awaited with bcp utilityRuntimeWarning:从未使用 bcp 实用程序等待协程
【发布时间】:2020-03-04 18:53:11
【问题描述】:

目标

使用asyncio,异步运行bcp 实用程序将多个表提取到.dat 文件。独立运行的命令会产生预期的结果。通过subprocess.run 进行顺序执行时,命令也成功执行。相信错误是由于我使用或不使用await的方式造成的。

错误

Traceback (most recent call last):
  File "bcp_out_all.py", line 38, in <module>
    asyncio.run(windows_loop([cmd_ for cmd_ in bcp_cmds]))
  File "C:\Users\hSin\AppData\Local\Continuum\anaconda3\envs\ELT\lib\asyncio\runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "C:\Users\hSin\AppData\Local\Continuum\anaconda3\envs\ELT\lib\asyncio\base_events.py", line 583, in run_until_complete
    return future.result()
  File "bcp_out_all.py", line 14, in windows_loop
    loop.run_until_complete(parallel_bcp(cmd_))
  File "C:\Users\hSin\AppData\Local\Continuum\anaconda3\envs\ELT\lib\asyncio\base_events.py", line 570, in run_until_complete
    self.run_forever()
  File "C:\Users\hSin\AppData\Local\Continuum\anaconda3\envs\ELT\lib\asyncio\base_events.py", line 528, in run_forever
    'Cannot run the event loop while another loop is running')
RuntimeError: Cannot run the event loop while another loop is running
sys:1: RuntimeWarning: coroutine 'parallel_bcp' was never awaited

脚本

#bcp_out_all.py
import asyncio

#commands successfully run in PowerShell terminal
bcp_cmds = [['bcp db.schema.tbl_1 OUT tbl_1.dat -e tbl_1_error.dat -T -n -t"|" -S SRVRNAME'], ['bcp db.schema.tbl_2 OUT tbl_2.dat -e tbl_2_error.dat -T -n -t"|" -S SRVRNAME']]


async def parallel_bcp(cmd_):
    process = await asyncio.create_subprocess_exec(cmd_, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
    await process.wait()

async def windows_loop(cmd_):
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(parallel_bcp(cmd_))

asyncio.run(windows_loop([cmd_ for cmd_ in bcp_cmds]))

【问题讨论】:

  • 您不需要在诸如windows_loop 之类的异步函数中使用run_until_complete - 您只需await parallel_bcp(cmd_)。或者,由于您的 cmd_ 实际上是一个列表,您应该使用类似 await asyncio.gather(*[parallel_bcp(c) for c in cmd_])

标签: python sql-server subprocess python-asyncio bcp


【解决方案1】:

能够根据这个问题找出解决方案; How do I pass a string in to subprocess.run using stdin in Python 3 但是,它的应用程序是关于 Python 3.7 和作为字符串列表传递的命令,我的命令列表被修改为。最后,subprocess 代替了asyncio

更新脚本:

from subprocess import Popen

procs_list = ['bcp db.schema.tbl_1 OUT tbl_1.dat -e tbl_1_error.dat -T -n -t"|" -S SRVRNAME', 'bcp db.schema.tbl_2 OUT tbl_2.dat -e tbl_2_error.dat -T -n -t"|" -S SRVRNAME']

for proc in procs_list:
   Popen(proc, text=True)

最终脚本:

最终不需要使用 asyncio,并利用了Popen

tbls_lst = ['tbl1', 'tbl2']

procs_lst = ['bcp db.schema.' + tbl + ' OUT ' + tbl + '.dat' + '-T -n -t"|" -S SRVRNAME -b 5000' for tbl in tbls_lst]

try:
    for proc in procs_lst:
        process = subprocess.Popen(
                proc,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True)
        output, error = process.communicate()
        if output:
            print("Output returned: ", process.returncode)
        if error:
            print("Error returned: ", process.returncode)
            print("Error:", error.strip())
except OSError as e:
    print("OSError: ", e.errno)
    print("OSError: ", e.strerror)
    print("OSError: ", e.filename)
except:
    print("Error: ", sys.exc_info()[0])

【讨论】:

  • 你能分享整个代码吗?我运行以下命令(基于您的示例):p=Popen(cmd, text=True) 然后process=await asyncio.create_subprocess_exec(cmd, ...) 然后await process.wait() 然后process.kill() 然后os.killpg(os.getpgid(p.id, signal.SIGTERM)) 这运行完美 BUT bcp.exe(在 Windows ) 继续在后台运行,并对数据库产生巨大影响。我不得不从cmd 中终止所有并行作业。因此,请提供完整的示例!谢谢!
  • @abe 我更新了脚本,最终选择了不同的路线。
  • 非常感谢。但这是否也异步运行?在我的版本中,我实现了producerconsumer。因此,producer 给出了例如 20 个表,例如有 10 个consumers。因此,我需要这段代码异步运行。
  • @abe 我相信确实如此,我已经有一段时间没有使用脚本了。
  • 好的,谢谢!最后一个问题,如何终止进程?我想念process.kill() 之类的东西......
猜你喜欢
  • 2018-10-26
  • 2021-10-22
  • 2019-12-15
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 2020-10-10
相关资源
最近更新 更多