RuntimeError: Задача получила будущееприкреплен к другой петле - PullRequest
0 голосов
/ 20 июня 2019

Как вызвать асинхронный метод, который получает цикл обработки событий в главном потоке внутри другого асинхронного метода в Quart?

t.py

from telethon import TelegramClient, functions, types

client2 = TelegramClient(sn, api_id, api_hash).start()

async def create_contact():
    return await client2(functions.contacts.ImportContactsRequest([
        types.InputPhoneContact(0, '8', 'first_name', 'last_name')
    ]))

app.py

from quart import Quart, websocket,render_template,request
import t2
app = Quart(__name__)

@app.route('/wa2tg')
def wa2tg():
    return render_template('wa2tg.html',nm=request.args.get('nm',''))

@app.websocket('/wa2tg2')
async def wa2tg2():
    while True:
        data = await websocket.receive()
        await t2.create_contact()

# Thread(target=tele.client2.run_until_disconnected).start()
app.run(debug=1)        

Ошибка:

Running on http://127.0.0.1:5000 (CTRL + C to quit)
[2019-06-21 16:31:42,035] 127.0.0.1:51696 GET /wa2tg 1.1 200 553 12995
[2019-06-21 16:31:42,486] 127.0.0.1:51698 GET /wa2tg2 1.1 101 - 999
[2019-06-21 16:31:42,490] ERROR in app: Exception on websocket /wa2tg2
Traceback (most recent call last):
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1629, in handle_websocket
    return await self.full_dispatch_websocket(websocket_context)
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1651, in full_dispatch_websocket
    result = await self.handle_user_exception(error)
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 948, in handle_user_exception
    raise error
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1649, in full_dispatch_websocket
    result = await self.dispatch_websocket(websocket_context)
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1694, in dispatch_websocket
    return await handler(**websocket_.view_args)
  File "D:\SmartBot\my_env\SmartBot\t.py", line 13, in wa2tg2
    await t2.create_contact()
  File "D:\SmartBot\my_env\SmartBot\t2.py", line 22, in create_contact
    types.InputPhoneContact(0, '8807328487', 'first_name', 'last_name')
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\telethon\client\users.py", line 60, in __call__
    result = await future
RuntimeError: Task <Task pending coro=<ASGIWebsocketConnection.handle_websocket() running at C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\asgi.py:135> cb=[_wait.<locals>._on_completion() at C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\asyncio\tasks.py:440]> got Future <Future pending> attached to a different loop

Как передать цикл событий в кварту? Я пытался получить цикл и установить внутри функции, но все равно получил ошибку

loop = asyncio.get_event_loop()
@app.websocket('/wa2tg2')
async def wa2tg2():
  while True:
    asyncio.set_event_loop(loop)
    data = await websocket.receive()
    await t2.create_contact()

Ответы [ 2 ]

1 голос
/ 21 июня 2019

Когда вы делаете:

TelegramClient(sn, api_id, api_hash)

Телетону нужно asyncio.get_event_loop(). Этот метод возвращает цикл события для текущего потока , который в вашем коде является основным потоком. Затем Telethon запоминает и использует цикл из основного потока .

Когда вы делаете:

Thread(target=tele.client2.run_until_disconnected).start()

Вы создаете новый поток, и по причинам, которые я объяснил, вы получаете соответствующую ошибку «Задача получила будущее, подключенное к другому циклу».

При использовании asyncio обычно не следует использовать threading, если вы действительно не знаете, что делаете.

На самом деле код можно переписать следующим образом (удалив все ненужные операции импорта, которые, вероятно, были добавлены без особого обдумывания):

Tele.py

from telethon import TelegramClient, functions, types

client = TelegramClient(sn, api_id, api_hash).start()

async def create_contact():
    return await client2(functions.contacts.ImportContactsRequest([
        types.InputPhoneContact(0, phone_number, first_name, last_name)
    ]))

app.py

from quart import Quart, websocket

app = Quart(__name__)

@app.websocket('/wa2tg2')
async def wa2tg2():
    while True:
        data = await websocket.receive()
        await tele.create_contact()

Несколько замечаний:

  • client.start() может работать без await.
  • client.run_until_disconnected() необходимо вызывать только в случае необходимости.
  • async def вызываются с помощью await, а не путем создания отдельного потока.
  • 0, который вы используете во входном контакте, будет работать только один раз (или не работать вообще), поскольку это должно быть случайное число.
  • Никогда не копируйте пасту вслепую. Поймите, что он делает первым.
0 голосов
/ 21 июня 2019

Решено после прохождения цикла до app.run

loop = asyncio.get_event_loop()
app.run(debug=1,loop=loop)        

Поток для client.run_until_disconnected() не нужен, так как мы передаем цикл в метод run

Подробнее о Telethon и Quart

...