2016-05-24 11 views
10

Sto tentando di utilizzare asyncio per eseguire un'installazione client/server asincrona.Python asyncio: la resa da non è stata utilizzata con il futuro?

Per qualche motivo, ricevo AssertionError: yield from wasn't used with future durante l'esecuzione del client.

La ricerca di questo errore non si è presentata molto.
Che cosa significa questo errore e che cosa lo sta causando?

#!/usr/bin/env python3 

import asyncio 
import pickle 
import uuid 

port = 9999 

class ClientProtocol(asyncio.Protocol): 
    def __init__(self, loop): 
     self.loop = loop 
     self.conn = None 
     self.uuid = uuid.uuid4() 
     self.other_clients = [] 

    def connection_made(self, transport): 
     print("Connected to server") 
     self.conn = transport 

     m = "hello" 
     self.conn.write(m) 

    def data_received(self, data): 
     print('Data received: {!r}'.format(data)) 


    def connection_lost(self, exc): 
     print('The server closed the connection') 
     print('Stop the event loop') 
     self.loop.stop() 



# note that in my use-case, main() is called continuously by an external game engine 
client_init = False 
def main(): 
    # use a global here only for the purpose of providing example code runnable outside of aforementioned game engine 
    global client_init 

    if client_init != True: 
     loop = asyncio.get_event_loop() 
     coro = loop.create_connection(lambda: ClientProtocol(loop), '127.0.0.1', port) 
     task = asyncio.Task(coro) 

     transport, protocol = loop.run_until_complete(coro) 

     client_init = True 

    # to avoid blocking the execution of main (and of game engine calling it), only run one iteration of the event loop 
    loop.stop() 
    loop.run_forever() 

    if transport: 
     transport.write("some data") 

if __name__ == "__main__": 
    main() 

Traceback:

Traceback (most recent call last): 
    File "TCPclient.py", line 57, in <module> 
    main() 
    File "TCPclient.py", line 45, in main 
    transport, protocol = loop.run_until_complete(coro) 
    File "/usr/lib/python3.5/asyncio/base_events.py", line 337, in run_until_complete 
    return future.result() 
    File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result 
    raise self._exception 
    File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step 
    result = coro.send(None) 
    File "/usr/lib/python3.5/asyncio/base_events.py", line 599, in create_connection 
    yield from tasks.wait(fs, loop=self) 
    File "/usr/lib/python3.5/asyncio/tasks.py", line 341, in wait 
    return (yield from _wait(fs, timeout, return_when, loop)) 
    File "/usr/lib/python3.5/asyncio/tasks.py", line 424, in _wait 
    yield from waiter 
    File "/usr/lib/python3.5/asyncio/futures.py", line 359, in __iter__ 
    assert self.done(), "yield from wasn't used with future" 
AssertionError: yield from wasn't used with future 
+1

In 'main()' crei 'task' da' coro' ma poi non lo uso - è quello che dovrebbe essere passato a 'loop.run_until_complete'? –

risposta

8

Il problema sembra essere che si crea un'attività dal coroutine, ma poi passa la coroutine a run_until_complete invece:

coro = loop.create_connection(lambda: ClientProtocol(loop), '127.0.0.1', port) 
    task = asyncio.Task(coro) 

    transport, protocol = loop.run_until_complete(coro) 

O passa il compito :

coro = loop.create_connection(lambda: ClientProtocol(loop), '127.0.0.1', port) 
    task = asyncio.Task(coro) 

    transport, protocol = loop.run_until_complete(task) 

Oppure non creare l'attività e passare la coroutine. run_until_complete creerà un compito per voi

coro = loop.create_connection(lambda: ClientProtocol(loop), '127.0.0.1', port) 

    transport, protocol = loop.run_until_complete(coro) 

Inoltre, è necessario garantire le corde si sta scrivendo sono stringhe di byte. I valori letterali delle stringhe in Python 3 sono predefiniti in Unicode. È possibile codificare questi, o semplicemente scrivere stringhe di byte, in primo luogo

EDIT Non è chiaro per me perché questo è un problema, ma la fonte di run_until_complete ha questo da dire:

ATTENZIONE: Sarebbe disastroso chiamare run_until_complete() con la stessa coroutine due volte - lo avvolgerebbe in due attività diverse e ciò non può essere positivo.

Suppongo che la creazione di un'attività e il passaggio della coroutine (che consente di creare un'attività) abbiano lo stesso effetto.

Problemi correlati