Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 27, 2020 11:00:57

Amperandus1
Зарегистрирован: 2020-02-27
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Добрый день.

Есть ли способ подружить pyqt и asyncio?

Задача: из gui сделать две кнопки - старт и стоп сервера. Код сервера запускается из QThread. Сделан на async/await. По отдельности все ок. Вместе не получается.

 #MainWindowQT
def btn_start(self):
        today = datetime.datetime.today()
        self.label_4.show()
        self.label_5.hide()
        self.btnStart.setDisabled(True)
        self.btnStop.setEnabled(True)
        self.serverThread.start()
        self.textBrowser.append(str(today.strftime("%Y-%m-%d %H:%M:%S   ") + 'INFO  Сервер запущен'))

 #ThreadQT
from PyQt5 import QtCore
import Model.Server
import asyncio
class ThreadServer(QtCore.QThread):
    sigServ = QtCore.pyqtSignal(str)
    def __init__(self,parent=None):
        QtCore.QThread.__init__(self,parent)
        self.running = False
    def run(self):
        self.running = True
        s = Model.Server.Server()
        while self.running:
            print('1' + str(self.running))
            asyncio.run(s.serverInit())#Отсюда нет возврата управления, что логично в общем то
            QtCore.QThread.sleep(1)
            print('2' + str(self.running))
        s.stop()
        print("stop")

 #Server
import asyncio
class Server():
    def __init__(self):
        self.host = '127.0.0.1'
        self.port = '9001'
    async def serverInit(self):
        self.server = await asyncio.start_server(self.readFromServer, self.host, self.port)
        await self.server.serve_forever()
    async def readFromServer(self,reader, writer):
        data = await reader.read(1024)
        print(f'Received: {data.decode()!r}')
    async def stop(self):
        self.server.close()

Выполнение останавливается на asyncio.run(s.serverInit()). Почитал что нашел - разные loop. Рекомендуют использовать сторонние, не особо понятные мне, библиотеки (например, asyncqt).

Пробовал делать await asyncio.run(s.serverInit()) - асинхронность поднимается до запуска основного окна на QT.

Есть ли другие варианты? Особого опыта написания на питоне нет. В принципе останется вариант работы без GUI из консоли - там все ок будет, но хотелось бы с кнопочками и окном.

Отредактировано Amperandus1 (Фев. 27, 2020 11:08:17)

Офлайн

#2 Фев. 27, 2020 12:13:57

AD0DE412
Зарегистрирован: 2019-05-12
Сообщения: 1130
Репутация: +  44  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

не очень дружу с python и qt но вот такие есть соображения ..

Программирование на Python, том 1, 4-е издание. Марк Лутц

Взаимодействия между процессами…………………………………316
Анонимные каналы………………………………………………..318
Именованные каналы (fifo)……………………………………….331
Сокеты: первый взгляд…………………………………………….335
Сигналы………………………………………………………………340

там же(не ну правда зачем вам ради двух кнопок qt?)

Обзор tkinter…………………………………………………………….490



1. пжлст, форматируйте код, это в панели создания сообщений, выделите код и нажмите что то вроде
2. чтобы вставить изображение залейте его куда нибудь (например), нажмите и вставьте ссылку на его url

есчщо

Офлайн

#3 Фев. 27, 2020 15:21:34

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2849
Репутация: +  186  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

         self.running = True
        s = Model.Server.Server()
        while self.running:
            print('1' + str(self.running))
            asyncio.run(s.serverInit())#Отсюда нет возврата управления, что логично в общем то
            QtCore.QThread.sleep(1)
            print('2' + str(self.running))
        s.stop()
Где у тебя выход из цикла while? У тебя asyncio.run(s.serverInit()) будет постоянно запускаться каждую милисекунду.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Отредактировано Rodegast (Фев. 27, 2020 15:54:56)

Офлайн

#4 Фев. 27, 2020 15:28:55

Amperandus1
Зарегистрирован: 2020-02-27
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Это меня устроит вполне. Он не возвращает управление сейчас в while. нужно решить эту проблему

Лутца я читал. Там немного не про то и устарело малость. Про tkinter читал опять же что лучше и не начинать с ним работать. Две кнопки это сейчас. В планах было дописать до большего функционала.

Пробовал с try except с выбросом исключений - тоже не взлетело.

Офлайн

#5 Фев. 27, 2020 17:38:17

AD0DE412
Зарегистрирован: 2019-05-12
Сообщения: 1130
Репутация: +  44  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Amperandus1
Лутца я читал
а я еще нет (еще не все т.е. пока читаю), но это не повод для гордости (для меня) … но это такое … неважное
по теме
Amperandus1
В принципе останется вариант работы без GUI из консоли - там все ок будет, но хотелось бы с кнопочками и окном.
попробую сказать более ясно …
похоже вы пытаетесь запуститься мультипоточно (я ошибаюсь?)
мне кажется что лучше будет запускать мультипроцессорно т.е. gui отдельно, сервер отдельно.
вот.
с управлением через gui по каналам или сокетам короче как вам будет лучше.



1. пжлст, форматируйте код, это в панели создания сообщений, выделите код и нажмите что то вроде
2. чтобы вставить изображение залейте его куда нибудь (например), нажмите и вставьте ссылку на его url

есчщо

Отредактировано AD0DE412 (Фев. 27, 2020 17:38:54)

Офлайн

#6 Фев. 27, 2020 20:42:23

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Amperandus1
По отдельности все ок. Вместе не получается.
Amperandus1
Выполнение останавливается на asyncio.run(s.serverInit())
Так непонятно что именно не получается. Выполнение треда останавливается. Так и должно быть. В чем проблема?

Amperandus1
не особо понятные мне, библиотеки (например, asyncqt).
А понимать особо нечего. В GUI есть event loop. В asyncio свой event loop. Если их будет оба, то будут трудности с их синхронизацией. библиотеки типа asyncqt делают общий event loop для всех асинхронных событий. Пользуйтесь и будет вам счастье.



Офлайн

#7 Фев. 28, 2020 06:26:12

Amperandus1
Зарегистрирован: 2020-02-27
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Значит придется копать в сторону библиотек. Просто хотел узнать - есть ли другие варианты (видимо нет).

Офлайн

#8 Фев. 28, 2020 07:01:13

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Amperandus1
Просто хотел узнать - есть ли другие варианты (видимо нет).
Как раз вариантов бесконечно много. НО!! Вы не написали почему считаете что оно не работает. Вы не написали как хотите эксплуатировать ваше приложение (способ обмена данными с кнопочками). А любые способы требуют понимания того что вы делаете и зачем.

Можно и с тредами сделать как у вас, но тогда нужны семафоры и посылка сообщений в eventloop asyncio.
Можно два процесса запустить и сокетами их связать.
Кнопочки в данном случае проще в вебе сделать а не в Qt
и т.д.

У каждого способа есть плюсы и минусы.



Офлайн

#9 Фев. 28, 2020 07:55:01

Amperandus1
Зарегистрирован: 2020-02-27
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Есть основной поток QT с кнопочками. Из него я запускаю QThread - второй поток, в котором запускаю асинхронный сервер. Вот в него мне бы хотелось получать обратно управление потому что хочу иметь возможность останавливать сервер. Потоки как раз сигналами связаны между собой. А вот как связать потоки pyqt и код сервера на asyncio я пока не нашел. Запустить да - получается, управлять - нет.

Есть еще QTcpSocket… в общем нужно выяснить в какую сторону лучше копать.

Смог остановить север. Не могу запустить второй раз. Один черт не возвращается управление… надо думать

Отредактировано Amperandus1 (Фев. 28, 2020 09:12:51)

Офлайн

#10 Фев. 28, 2020 11:36:06

Amperandus1
Зарегистрирован: 2020-02-27
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyqt + Asyncio

Не знаю насколько правильное решение с прерыванием потока, но работает.

  
class ThreadServer(QtCore.QThread):
    sigServ = QtCore.pyqtSignal(str)
    def __init__(self,parent=None):
        QtCore.QThread.__init__(self,parent)
        self.running = False
        self.s = Model.Server.Server()
    def run(self):
        print('start')
        asyncio.run(self.s.serverInit())
        print('2')
    def stop(self):
        self.s.stop()
        self.terminate()

 import asyncio
class Server():
    def __init__(self):
        self.host = '127.0.0.1'
        self.port = '9001'
    async def serverInit(self):
        self.server = await asyncio.start_server(self.readFromServer, self.host, self.port)
        await self.server.serve_forever()
    async def readFromServer(self,reader, writer):
        data = await reader.read(1024)
        print(f'Received: {data.decode()!r}')
    def stop(self):
        self.server.close()

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version