asyncio 的性能
Performance of asyncio
我正在尝试熟悉 asyncio,所以我决定编写一个数据库客户端。但是,性能与同步代码完全匹配。我确定这是我对一个概念的误解。有人可以解释我在做什么吗?
请看下面的代码示例:
class Connection:
def __init__(self, reader, writer, loop):
self.futures = deque()
# ...
self.reader_task = asyncio.async(self.recv_data(), loop=self.loop)
@asyncio.coroutine
def recv_data(self):
while 1:
try:
response = yield from self.reader.readexactly(4)
size, = struct.unpack('I', response)
response = yield from self.reader.readexactly(size)
# ...
future = self.futures.popleft()
if not future.cancelled():
future.set_result(response)
except Exception:
break
def send_data(self, data):
future = asyncio.Future(loop=self.loop)
self.futures.append(future)
self.writer.write(data)
return future
loop = asyncio.get_event_loop()
@asyncio.coroutine
def benchmark():
connection = yield from create_connection(loop=loop, ...)
for i in range(10000):
yield from connection.send_data(...)
s = time.monotonic()
loop.run_until_complete(benchmark())
e = time.monotonic()
print('Requests per second:', int(10000 / (e - s)))
提前致谢。
python asyncio 模块是单线程的:
This module provides infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related primitives.
This question 解释了为什么 asyncio 可以比线程慢,但简而言之:asyncio 使用单个线程来执行你的代码,所以即使你有多个协程,它们也都是串行执行的。线程池用于执行一些回调和I/O。由于 GIL,线程也串行执行用户代码,尽管 I/O 操作可以 运行 同步。
使用 asyncio 并没有给你带来比串行执行代码更好的原因,是因为事件循环一次只运行一个协程。
您的调用方式有误send_data
。现在,你得到了这个:
@asyncio.coroutine
def benchmark():
connection = yield from create_connection(loop=loop, ...)
for i in range(10000):
yield from connection.send_data(...)
通过在 for 循环中使用 yield from
,您将等待从 send_data
返回的 future
产生结果,然后再继续下一个调用。这使您的程序基本上是同步的。您想对 send_data
进行所有调用,然后 然后 等待结果:
@asyncio.coroutine
def benchmark():
connection = yield from create_connection(loop=loop, ...)
yield from asyncio.wait([connection.send_data(..) for _ in range(10000)])
我正在尝试熟悉 asyncio,所以我决定编写一个数据库客户端。但是,性能与同步代码完全匹配。我确定这是我对一个概念的误解。有人可以解释我在做什么吗?
请看下面的代码示例:
class Connection:
def __init__(self, reader, writer, loop):
self.futures = deque()
# ...
self.reader_task = asyncio.async(self.recv_data(), loop=self.loop)
@asyncio.coroutine
def recv_data(self):
while 1:
try:
response = yield from self.reader.readexactly(4)
size, = struct.unpack('I', response)
response = yield from self.reader.readexactly(size)
# ...
future = self.futures.popleft()
if not future.cancelled():
future.set_result(response)
except Exception:
break
def send_data(self, data):
future = asyncio.Future(loop=self.loop)
self.futures.append(future)
self.writer.write(data)
return future
loop = asyncio.get_event_loop()
@asyncio.coroutine
def benchmark():
connection = yield from create_connection(loop=loop, ...)
for i in range(10000):
yield from connection.send_data(...)
s = time.monotonic()
loop.run_until_complete(benchmark())
e = time.monotonic()
print('Requests per second:', int(10000 / (e - s)))
提前致谢。
python asyncio 模块是单线程的:
This module provides infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related primitives.
This question 解释了为什么 asyncio 可以比线程慢,但简而言之:asyncio 使用单个线程来执行你的代码,所以即使你有多个协程,它们也都是串行执行的。线程池用于执行一些回调和I/O。由于 GIL,线程也串行执行用户代码,尽管 I/O 操作可以 运行 同步。
使用 asyncio 并没有给你带来比串行执行代码更好的原因,是因为事件循环一次只运行一个协程。
您的调用方式有误send_data
。现在,你得到了这个:
@asyncio.coroutine
def benchmark():
connection = yield from create_connection(loop=loop, ...)
for i in range(10000):
yield from connection.send_data(...)
通过在 for 循环中使用 yield from
,您将等待从 send_data
返回的 future
产生结果,然后再继续下一个调用。这使您的程序基本上是同步的。您想对 send_data
进行所有调用,然后 然后 等待结果:
@asyncio.coroutine
def benchmark():
connection = yield from create_connection(loop=loop, ...)
yield from asyncio.wait([connection.send_data(..) for _ in range(10000)])