3

我创建了一个套接字对象socket(AF_INET, SOCK_DGRAM),我将在异步循环中使用它。但是我在https://docs.python.org/3/library/asyncio-eventloop.html#low-level-socket-operations中找不到sendto函数。

我可以安全地假设这个函数是一个可以在 asyncio 循环中调用的非阻塞系统调用吗?或者我应该提交它以在另一个线程中运行run_in_executor

**文档指出它执行了一个系统调用,这让我担心它可能会阻塞整个循环。

4

2 回答 2

4

不,你不能期望socket.sendto是非阻塞的。

相反,使用DatagramTransport.sendto

将数据字节发送到由 addr(传输-> 依赖目标地址)给定的远程对等方。如果 addr 为 None,则数据将发送到创建传输时给定的目标地址。

该方法不阻塞;它缓冲数据并安排将其异步发送出去。

数据报传输由loop.create_datagram_endpoint协程返回:

transport, protocol = await loop.create_datagram_endpoint(factory, sock=sock)

编辑 - 关于您的评论:

socket.sendto() 是否等同于 transport.sendto()?

不,不是,transport.sendto用于loop.add_writer使操作非阻塞。请参阅实施

我不想使用这种方法,因为它的实现强制我通过具有回调样式的协议接收数据。

较低级别的 asyncio 基于回调,并且 asyncio 不为 UDP 提供基于协程的对象。但是,我编写了一个模块,为 asyncio 提供高级 UDP 端点

用法:

async def main():
    local = await open_local_endpoint()
    remote = await open_remote_endpoint(*local.address)
    remote.write(b'Hey Hey, My My')
    data, addr = await local.read()
    message = "Got {data!r} from {addr[0]} port {addr[1]}"
    print(message.format(data=data.decode(), addr=addr))

输出:

Got 'Hey Hey, My My' from 127.0.0.1 port 45551
于 2016-10-17T14:26:09.450 回答
-1

sendto()是非阻塞的,如果 writer 当前不可用,可能会引发 ( BlockingIOError, )。和InterruptedError之间的区别在于它将首先尝试调用,或者等到套接字准备好写入并在第一次尝试发送失败时再次调用。socket.sendto()transport.sendto()transport.sendto()socket.sendto()loop.add_writer()socket.sendto()

这是我从 Python 3.5.2 (Windows 32bit) 的 asyncio 模块的源代码中观察到的

编辑:

在 Windows 中,socket 操作阻塞行为由 指定socket.settimeout,因此请确保将超时值设置为0,使其操作不会阻塞。

于 2016-10-18T12:16:42.060 回答