标签: python-asyncio

如何在异步代码异常时启动 pdb

我有一个 asyncio 应用程序,其中发生了一些异常。

让我们以这个小脚本为例:

import asyncio

async def coro1():
    for a in range(1, -1, -1):
       await asyncio.sleep(1)
       print("coro1", a)
       c = 1/a  # ### !!!Will raise exception when a is 0!!!!

async def coro2():
    for n in range(6):
        print("------- coro2", n)
        await asyncio.sleep(0.5)

async def main():
    coros = [coro1(), coro2()]
    completed, pending = await asyncio.wait(coros)
    print("comp", completed)
    print("pend", pending)

event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)

如果我对单线程非异步程序遇到类似的问题,我就会这样做

python -m pydb scriptname
Run Code Online (Sandbox Code Playgroud)

输入c并在代码中以 pydb 结束,这引发了异常,现在我可以查看和显示变量,我可以看到例如,那a是 0

我在我的 asyncio 应用程序中尝试了同样的操作,

我仅在 …

python pdb python-asyncio

5
推荐指数
0
解决办法
2117
查看次数

异步在另一个任务中启动一个任务?

我正在尝试学习 asyncio 的用法,但遇到了障碍。

我想做什么?我正在尝试创建其中的一些,workers一旦它们被创建,他们就开始自己的task. 因此,在task3创建并启动时task1应该已经在执行其任务。我通过在单个 内使用循环来做到这一点coroutine,在每次迭代时worker创建并启动。

我面临的问题:当第一个工作人员完成其任务时,其他工作人员只是停止而不继续。

这是我的代码:

import asyncio

class Worker:
    def __init__(self, session_name):
        self.name = session_name
        self.messagelist = ['--------1', '--------2', '--------3', '--------4']

    async def job(self):
        for i, message in enumerate(self.messagelist):
            print(f"### Worker {self.name} says {message}")
            await asyncio.sleep(20)

class Testmanager:
    def __init__(self):
        self.workers_name = ['test0', 'test1', 'test2', 'test3', 'test4']

    async def create_and_start_workers(self, loop):
        for i, name in enumerate(self.workers_name):
            worker = Worker(name)
            print(f"# Created worker {worker.name}")
            loop.create_task(worker.job())
            print(f"## …
Run Code Online (Sandbox Code Playgroud)

task python-asyncio python-3.7

5
推荐指数
1
解决办法
3012
查看次数

如何检测 asyncio.StreamWriter.write 上关闭的套接字?

我终于开始学习 python 了asyncio,并且正在创建一个简单的客户端服务器。我可以轻松地使用open_connection和start_server并让一切都在说话。但是,当一侧意外关闭连接时,我遇到了一些意外行为。

在客户端,我可以轻松检测到服务器关闭了连接,因为任何对StreamReader.read等待的调用要么出错,要么不返回任何内容。然而,无论对方是否仍然打开套接字,StreamWriter.write/调用似乎都会成功,这让我感到困惑。await StreamWriter.drain

客户端(在协程中,通过以下方式调用run_until_complete:

_, writer = await asyncio.open_connection('127.0.0.1', 1234)
_ = input('Connected.  Type and press enter to attempt send.')

try:
    writer.write(b'A message')
    await writer.drain()
    print('Sent successfully.')

except:
    print(traceback.print_exc())
finally:
    writer.close()
    await writer.wait_closed()
Run Code Online (Sandbox Code Playgroud)

服务器(同步版本,我也尝试过异步服务器):

with socket.socket() as s:
    s.bind(('0.0.0.0', 1234))
    s.listen(1)

    con, addr = s.accept()
    with con:
        print(f'Connected to {addr[0]}:{addr[1]}')
        _ = input('Type and press Enter to close.')

Run Code Online (Sandbox Code Playgroud)

如果我启动服务器,连接客户端,然后让服务器终止连接,然后告诉客户端写入,我希望根据文档和此 StackOverflow 帖子收到异常,但客户端只是打印Sent successfully. …

python python-3.x python-asyncio

5
推荐指数
1
解决办法
2729
查看次数

使用 websocket.send(msg) 一段时间时出现“将 Future <Futureending> 附加到不同的循环”错误

我正在使用 websocket 在 python 中发送和接收消息。我使用“websocket.send(msg)”以这些形式发送消息:

await ws.send(message)
Run Code Online (Sandbox Code Playgroud)

和

asyncio.run(ws.send(message))
Run Code Online (Sandbox Code Playgroud)

在 while 循环中,我首先检查连接是否处于活动状态,然后使用这些命令发送消息。在所有这些中,如果发送次数较少,没有问题,但是当发送次数增加时,我会收到发送消息的异常

Task <Task pending coro=<RunSocket() running at <ipython-input-1-b17eaf75a3de>:182> cb=[_run_until_complete_cb() at D:\Anaconda\InstallationFolder\lib\asyncio\base_events.py:158]> got Future <Future pending> attached to a different loop
Run Code Online (Sandbox Code Playgroud)

“请注意,RunSocket 是我的函数名称之一”

然后我得到这个错误:

got Future <Future pending> attached to a different loop
Run Code Online (Sandbox Code Playgroud)

我也尝试过这段代码:

asyncio.ensure_future(await ws.send(message))
Run Code Online (Sandbox Code Playgroud)

但它没有发送任何消息。谁能帮我解决这个错误?任何帮助将不胜感激。

python runtime-error websocket async-await python-asyncio

5
推荐指数
1
解决办法
9753
查看次数

Asyncio RuntimeError:当另一个协程已经在等待传入数据时调用 readuntil()

使用python3.6.8:

我正在尝试编写启动时网络设备初始配置的脚本。我的脚本在“ip_addr:port”上打开 telnet 连接。连接后,脚本会使用“\n\n”刺激其连接的网络设备(模拟管理员的两个“Enter”输入)。

connection = asyncio.open_connection(
                 ip_addr,
                 port,
             )
try:
    reader, writer = await asyncio.wait_for(connection, 5)
    print(f"successfully connected to {ip_addr}:{port}")
    writer.write(b'\n\n\n')
Run Code Online (Sandbox Code Playgroud)

一些设备已经配置,我除了“login:”之外,在输入“\n”时显示在读取缓冲区中。但是,如果设备尚未配置,“login:”将不会显示在缓冲区中。因此,我认为我可以使用 wait_for 和 timeout 选项来取消此操作,并继续使用另一个reader.readuntil(...)期待另一个输出。

try:
    await asyncio.wait_for(reader.readuntil(b' login: '), 3)
    print(f"{ip_addr}:{port} alredy booted")
    break
except (asyncio.TimeoutError, OSError):
    print('Nope, moving forward')
    await reader.readuntil(b'normal setup ?(yes/no)[n]: ')
Run Code Online (Sandbox Code Playgroud)

然而这会引发运行时错误。阅读文档时,我发现如果达到超时,任务就会被取消,那么为什么它不能有另一个协程readuntil()呢?

python-asyncio

5
推荐指数
1
解决办法
1559
查看次数

Python - 如何取消 python-trio 中托儿所生成的特定任务

我有一个监听特定端口的异步函数。我想一次在几个端口上运行该函数,当用户想要停止在特定端口上侦听时,停止在该端口上侦听的函数。

之前我使用 asyncio 库来完成此任务,并通过创建以唯一 id 作为名称的任务来解决此问题。

asyncio.create_task(Func(), name=UNIQUE_ID)
Run Code Online (Sandbox Code Playgroud)

由于 trio 使用 Nursery 来生成任务,我可以使用 Nursery.child_tasks 查看正在运行的任务,但这些任务没有办法命名它们,甚至没有办法按需取消任务

长话短说

由于 trio 没有取消特定任务的 cancel() 函数,因此如何手动取消任务。

python python-asyncio python-trio

5
推荐指数
1
解决办法
1408
查看次数

Gunicorn gevent:线程中没有当前事件循环

我有一个使用 async io 对不同服务执行并行请求的应用程序。这是一个用Gunicorn运行的flask APP。

不幸的是,有些请求有点长(长达 10 秒)。到目前为止,我一直在使用 Gunicorn 的基础工作人员(同步),但由于它们的数量有限,我有时会用完它们。

所以我听说过 gevent 工作类,对于大多数请求,它允许我并行处理,但我不明白应该如何使用 asyncio 处理代码。我用这个简单的例子重现了我的问题:

我使用这个命令来启动服务器:

gunicorn test_wsgi:app --config=test_wsgi_config.py
Run Code Online (Sandbox Code Playgroud)

使用 test_wsgi.py:

import asyncio

from flask import Flask

app = Flask(__name__)


async def a_long_task():
    await asyncio.sleep(5)


@app.route('/')
def hello():
    loop = asyncio.get_event_loop()

    loop.run_until_complete(
        loop.create_task(a_long_task())
    )

    return f'Hello, world'
Run Code Online (Sandbox Code Playgroud)

和 test_wsgi_config.py

worker_class = "gevent"
Run Code Online (Sandbox Code Playgroud)

当我使用worker_class =sync时,它工作正常,但所有请求都排队。但有了 gevent,我一直有:

RuntimeError: There is no current event loop in thread 'DummyThread-1'
Run Code Online (Sandbox Code Playgroud)

如果我创建一个事件循环:

@app.route('/')
def hello():
    asyncio.set_event_loop(asyncio.new_event_loop())
    loop = asyncio.get_event_loop()

    loop.run_until_complete(
        loop.create_task(a_long_task())
    )

    return f'Hello, world'
Run Code Online (Sandbox Code Playgroud)

我得到: …

python gunicorn python-asyncio

5
推荐指数
1
解决办法
1922
查看次数

asyncio.gather(*tasks) 未能仅等待所有任务的子集

要解决的问题(简化)

假设我有 26 个任务要并行运行。为了最大限度地减少服务器上的负载,我决定一次运行 10 个任务:首先并行运行 10 个任务,然后是接下来的 10 个任务,最后是剩余的 6 个任务。

我编写了一个简单的脚本来实现此行为:

import asyncio
from string import ascii_uppercase
from typing import List

TASK_NAMES = ascii_uppercase  # 26 fake tasks in total


class BatchWorker:
    """Run a list of tasks in batch."""

    BATCH_SIZE = 10

    def __init__(self, tasks: List[asyncio.Task]):
        self._tasks = list(tasks)

    @property
    def batch_of_tasks(self):
        """Yield all tasks by chunks of `BATCH_SIZE`"""
        start = 0
        while 'there are items remaining in the list':
            end = start + self.BATCH_SIZE
            chunk = self._tasks[start:end] …
Run Code Online (Sandbox Code Playgroud)

python asynchronous async-await python-asyncio

5
推荐指数
1
解决办法
3413
查看次数

我应该如何设置 aiomysql 池缓存?

当我使用mysql_poolfromaiomysql更新一条数据时,第一次和第二次是一样的。

\n
class Test(object):\n    async def _pool(self):\n        self.pool = await aiomysql.create_\xc3\xa7(**mysql_options)\n\n    async def get_one(self, sql, param=None):\n        await self.cur.execute(sql, param)\n        result = await self.cur.fetchone()\n        return result\n\n    async def get(self):\n        self.conn = await self.pool.acquire()\n        self.cur = await self.conn.cursor(DictCursor)\n        sql = \'\'\'select policy from tb_user where id = 2;\'\'\'\n        res = await self.get_one(sql)\n        print(res)\n        await self.cur.close()\n        await self.pool.release(self.conn)\n\n    @staticmethod\n    def update():\n        import pymysql\n        coon = pymysql.connect(host=\'127.0.0.1\',\n                               port=3306,\n                               user=mysql_options[\'user\'],\n                               autocommit=True,\n                               password=mysql_options[\'password\'],\n                               database=mysql_options[\'db\'])\n        cursor = coon.cursor()\n        sql = \'\'\'update tb_user set …
Run Code Online (Sandbox Code Playgroud)

python mysql python-asyncio aio-mysql

5
推荐指数
1
解决办法
1186
查看次数

处理 websockets 模块异常和错误

我正在尝试使用 Python 中的 websockets 模块创建一个简单的 WebSocket 服务器。

我的任务是创建一个 WebSocket 服务器,向所有正在侦听它的客户端发送消息。问题是,每次客户端断开连接时,websockets 都会启动一个异常(ConnectionClosedOK或ConnectionClosedError,取决于发生的情况),我需要捕获该异常,因为我必须取消注册已断开连接的客户端,以便 WebSocket 停止在以太中发送消息(并停止WebSocket 服务器每次尝试向已关闭的客户端发送消息时都会抛出这些异常)。

这是服务器的代码:

async def foo_call():
    await asyncio.sleep(3)
    print('Hi!')


async def register(websocket):
    users.add(websocket)
    await notify_users()


async def unregister(websocket):
    users.remove(websocket)


async def start(websocket, path):
    await register(websocket)

    try:
        await foo_call()
    except websockets.ConnectionClosedError:
        await unregister(websocket)


# WebSocket clients that are listening this WebSocket server
users = set()

# Open WebSocket server
start_server = websockets.serve(start, "localhost", 8765)

# Run asyncio event loop
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Run Code Online (Sandbox Code Playgroud)

这是回溯:

Task exception was …
Run Code Online (Sandbox Code Playgroud)

python exception websocket python-asyncio

5
推荐指数
0
解决办法
4160
查看次数