소켓 모듈은 socket.recv_into
방법을 가지고 있으므로 0- 복사를 위해 사용자 정의 bytebuffer
(예 : bytearray
)을 사용할 수 있습니다. 하지만 아마도 BaseEventLoop
에는 그런 방법이 없습니다. asyncio에서 socket.recv_into
과 같은 메서드를 사용할 수 있습니까?python 3 asyncio에서 socket.recv_into와 같은 연산이 있습니까?
답변
BaseEventLoop
에 대해 정의 된 하위 수준의 소켓 작업에는 socket.socket
개체가 전달되어야합니다. BaseEventLoop.sock_recv(sock, nbytes)
. 따라서 socket.socket
이 있으니 sock.recv_into()
으로 전화 할 수 있습니다. 그것을하는 것이 좋은 생각인지 여부가 또 하나의 질문입니다. 지금 asyncio .recv_into()
아웃 - 박스를 사용하는 방법을되지 않았습니다
당신 은, .recv_into()
기능을 이용하여 자신의 asyncio 전송을 구현하지만, 예 수 있습니다.
개인적으로 나는 매우 큰 스피드 업에 의문을 가지고 있습니다. C로 개발할 때 제로 카피는 매우 중요하지만 파이썬 이점과 같은 고급 언어는 훨씬 적습니다.
업데이트 :이 글을 쓰면서 알파 버전 인 Python 3.7.0부터 표준 라이브러리의 asyncio 모듈은 AbstractEventLoop.sock_recv_into()를 문서화합니다. 같은 요청에 따라
호출의 asyncio 할 ... 답을 확장 sock_recv_into()
은 일반적으로 보인다 :
편집
byte_count = await loop.sock_recv_into(sock, buff)
버프는 파이썬의 버퍼 프로토콜을 구현하는 변경 가능한 개체입니다, 예는의를 포함 bytearray 및 bytearray에 memoryview. 아래 코드는 메모리 뷰를 사용하여 bytearray에 수신하는 방법을 보여줍니다.
asyncio 소켓의 데모 코드에는 연결의 양쪽을 설정하고 이벤트 루프를 실행하는 일련의 스 캐 폴딩이 필요합니다. 요점은 아래의 sock_read_exactly() 공동 루틴에서 asyncio의 sock_recv_into()를 사용하는 것입니다.
#!/usr/bin/env python3
"""Demo the asyncio module's sock_recv_into() facility."""
import sys
assert sys.version_info[:2] >= (3, 7), (
'asyncio sock_recv_into() new in Python 3.7')
import socket
import asyncio
def local_echo_server(port=0):
"""Trivial treaded echo server with sleep delay."""
import threading
import time
import random
ssock = socket.socket()
ssock.bind(('127.0.0.1', port))
_, port = ssock.getsockname()
ssock.listen(5)
def echo(csock):
while True:
data = csock.recv(8192)
if not data:
break
time.sleep(random.random())
csock.sendall(data)
csock.shutdown(1)
def serve():
while True:
csock, client_addr = ssock.accept()
tclient = threading.Thread(target=echo, args=(csock,), daemon=True)
tclient.start()
tserve = threading.Thread(target=serve, daemon=True)
tserve.start()
return port
N_COROS = 100
nrunning = 0
async def sock_read_exactly(sock, size, loop=None):
"Read and return size bytes from sock in event-loop loop."
if loop is None: loop = asyncio.get_event_loop()
bytebuff = bytearray(size)
sofar = 0
while sofar < size:
memview = memoryview(bytebuff)[sofar:]
nread = await loop.sock_recv_into(sock, memview)
print('socket', sock.getsockname(), 'read %d bytes' % nread)
if not nread:
raise RuntimeError('Unexpected socket shutdown.')
sofar += nread
return bytebuff
async def echo_client(port):
"Send random data to echo server and test that we get back the same."
from os import urandom
global nrunning
loop = asyncio.get_event_loop()
sock = socket.socket()
sock.setblocking(False)
await loop.sock_connect(sock, ('127.0.0.1', port))
for size in [1, 64, 1024, 55555]:
sending = urandom(size)
await loop.sock_sendall(sock, sending)
received = await sock_read_exactly(sock, size)
assert received == sending
nrunning -= 1
if not nrunning:
loop.stop()
if __name__ == '__main__':
port = local_echo_server()
print('port is', port)
loop = asyncio.get_event_loop()
for _ in range(N_COROS):
loop.create_task(echo_client(port))
nrunning += 1
print('Start loop.')
loop.run_forever()
'AbstractEventLoop.sock_recv_into()'를 사용 하시겠습니까? 아마도 코드 샘플을 포함 할 것입니다. –
이미'loop.sock_recv'을 사용하고 있습니다. 그러나'loop.sock_recv'는 bytes 객체를 반환합니다. 그래서 저는'bytearray.extend method'도 사용합니다. ex) 'ba = bytearray(); bytes_object = yield from loop.sock_recv (some_sock); ba.extend (bytes_object) ' 'sock_recv'는 사전 생성 된 고정 크기 'bytearray'를 사용하지 않습니다. –
나는'precreated_buffer = bytearray (b ''* 100)와 같은 방식을 원한다. loop.sock_recv_into (some_socket, precreated_buffer, 100)' –
@SungHyunHwang : 나는'loop.sock_recv()'대신에''socket.recv_into()'_를 소켓에 호출 할 수 있다고 제안했다. 나는 그것이 asyncio 프레임 워크 내에서하는 것이 안전한 것인지 전혀 모른다 - 나는 의심한다. – mhawke