2016-10-17 4 views
2

У меня есть объект сокета, созданный с помощью socket(AF_INET, SOCK_DGRAM), который я буду использовать в цикле asyncio. Однако я не смог найти функцию sendto в https://docs.python.org/3/library/asyncio-eventloop.html#low-level-socket-operations.Можно ли предположить, что socket.sendto является неблокирующей операцией?

Можно ли с уверенностью предположить, что эта функция является неблокирующим системным вызовом, который может быть вызван внутри цикла asyncio? Или я должен отправить его для запуска в другом потоке с run_in_executor?

** Documentation утверждает, что он выполняет системный вызов, который касался меня тем, что он может блокировать весь цикл.

+0

[2432814] (http://stackoverflow.com/questions/2432814/python-blocking-sockets-send-returns-immediately) дублировать? – ldavid

+1

извините за то, что упустил этот пост с 'search Q & A'. Я искал такие ключевые слова, как «is sendto non-blocking», «is sendto safe to use in asyncio loop» .. и т. Д. – SpringMaple

ответ

3

Нет, вы не можете ожидать, что socket.sendto будет неблокирующим.

Вместо этого используйте DatagramTransport.sendto:

Отправить байты данных удаленного узла, заданного адром (а транспортно> зависит от целевого адреса). Если addr равно None, данные отправляются на целевой адрес, указанный при создании транспорта.

Этот метод не блокирует; выполняет буферизацию данных и организует их отправку асинхронно.

Датаграмма транспорт возвращается в loop.create_datagram_endpoint сопрограмме:

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

EDIT - О Вашем комментарии:

Is socket.sendto() эквивалентен transport.sendto ()?

Нет, это не так, transport.sendto использует loop.add_writer, чтобы сделать операцию неблокирующей. См. implementation.

Я не хочу использовать этот метод из-за его реализации, который принуждает меня принимать данные через протокол с обратным вызовом.

Более низкий уровень asyncio основан на обратных вызовах, и asyncio не предоставляет объекты на основе coroutine для UDP. Тем не менее, я написал module that provides high-level UDP endpoints for asyncio.

Использование:

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 
+0

Is socket.sendto() эквивалентен transport.sendto()? Я не хочу использовать этот метод из-за его реализации, который принуждает меня получать данные через «протокол» с обратным вызовом. Я хотел бы сделать [sendto ... recv ... recv ... (loop), затем сделать что-то ,,,] все в одной функции, а не разбросано. BTW Я приму это как решение, спасибо! – SpringMaple

+0

@SpringMaple Нет проблем, см. Мое редактирование. – Vincent

+0

Спасибо, ваш модуль мне очень помог. – SpringMaple

-1

sendto() неблокирующая, и может поднять (BlockingIOError, InterruptedError), если автор в настоящее время недоступен. Разница между socket.sendto() и transport.sendto() заключается в том, что transport.sendto() попытается позвонить по телефону socket.sendto(), или дождитесь, пока сокет будет готов к записи с loop.add_writer() и вызовет socket.sendto(), если он не был отправлен при первой попытке.

Это то, что я наблюдал из исходного кода в модуле asyncio для Python 3.5.2 (Windows 32bit)

EDIT:

В Windows, операция сокета блокировки поведение определяется socket.settimeout, поэтому убедитесь, чтобы установить значение тайм-аута для 0 так, что его операции не блокируют.

Смежные вопросы