Python asyncio协议竞争条件

西蒙妮·布朗齐尼

考虑以下代码(解释如下):

import asyncio

class MyClass(object):
    def __init__(self):
        self.a = 0
    def incr(self, data):
        self.a += 1
        print(self.a)

class GenProtocol(asyncio.SubprocessProtocol):
    def __init__(self, handler, exit_future):
        self.exit_future = exit_future
        self.handler = handler

    def pipe_data_received(self, fd, data):
        if fd == 1:
            self.handler(data)
        else:
            print('An error occurred')

    def process_exited(self):
        self.exit_future.set_result(True)

def start_proc(stdout_handler, *command):
    loop = asyncio.get_event_loop()
    exit_f = asyncio.Future(loop=loop)
    subpr = loop.subprocess_exec(lambda: GenProtocol(stdout_handler, exit_f),
                                 *command,
                                 stdin=None)
    transport, protocol = loop.run_until_complete(subpr)

    @asyncio.coroutine
    def waiter(exit_future):
        yield from exit_future

    return waiter, exit_f

def main():
    my_instance = MyClass()
    loop = asyncio.get_event_loop()
    waiter, exit_f = start_proc(my_instance.incr, 'bash', 'myscript.sh')
    loop.run_until_complete(waiter(exit_f))
    loop.close()

if __name__ == '__main__':
    main()

组件的简要说明如下:

  1. MyClass 非常简单
  2. GenProtocol 是一个类,它允许为子流程的stdout上接收的数据指定自定义处理程序。
  3. start_proc 允许您通过以下方式启动自定义过程,为在stdout上接收的数据指定自定义处理程序 GenProtocol
  4. my_proc 是一个永远运行的过程,可以在任意时间将数据发送到管道

现在,我的问题是:由于我将方法用作处理程序,并且由于该方法以非原子方式更改实例属性,因此这是否潜在危险?例如,当我在子进程的管道上异步接收数据时,该处理程序是并发调用两次(因此有可能损坏MyClass.a中的数据)还是被序列化了(即第二次调用该处理程序,直到该处理程序才执行首先完成)?

安德鲁·斯维特洛夫(Andrew Svetlov)

协议方法是常规功能,而不是协程。他们里面没有屈服点

因此,执行顺序非常简单:所有调用都已序列化,没有竞争条件。

UPD

在该示例pipe_data_received()中,不是协程,而是没有await/yield from内部的函数

asyncio 始终一次执行整个过程,而无需在中间进行任何上下文切换。

您可能认为这pipe_data_received()是受锁保护的,但实际上该案例不需要任何锁。

当您拥有这样的协同程序时,必须使用锁:

async def incr(self):
    await asyncio.sleep(0.1)
    self.counter +=1

在后者中incr()是一个协程,此外,随时可以进行上下文切换sleep()如果要保护并行增量,可以使用asyncio.Lock()

def __init__(self):
    self.counter = 0
    self.lock = asyncio.Lock()

async def incr(self):
    async with self._lock:
        await asyncio.sleep(0.1)
        self.counter +=1

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

编写异步HTTP库是否需要Python的AsyncIO协议?

来自分类Dev

python asyncio中的协议工厂有什么要求?

来自分类Dev

有GIL时,您可以在Python中竞争条件吗?

来自分类Dev

有GIL时,您可以在Python中竞争条件吗?

来自分类Dev

多线程Web服务器上的python + wsgi:这是竞争条件吗?

来自分类Dev

如何在此python代码中可靠地复制竞争条件?

来自分类Dev

多线程Web服务器上的python + wsgi:这是竞争条件吗?

来自分类Dev

Python Asyncio-等待条件满足的Pythonic方法

来自分类Dev

与.ContinueWith()的竞争条件

来自分类Dev

setpgid的竞争条件

来自分类Dev

异步网络竞争条件

来自分类Dev

WebAPI防止竞争条件

来自分类Dev

ConcurrentBitSet中的竞争条件

来自分类Dev

Postgresql竞争条件

来自分类Dev

与printf的OpenCL竞争条件?

来自分类Dev

java ThreadPool竞争条件

来自分类Dev

信号之间的竞争条件

来自分类Dev

使用 __block 竞争条件

来自分类Dev

AtomicLong 可能的竞争条件?

来自分类Dev

如何触发竞争条件?

来自分类Dev

Python3 asyncio“任务已销毁,但正在挂起”,具有某些特定条件

来自分类Dev

Python asyncio简单示例

来自分类Dev

Python的asyncio同步工作

来自分类Dev

Python asyncio调试示例

来自分类Dev

发送邮件python asyncio

来自分类Dev

python asyncio aiohttp超时

来自分类Dev

asyncio(python)如何工作?

来自分类Dev

理解python中的asyncio

来自分类Dev

Python asyncio 等待任务