Задать вопрос
paulenot
@paulenot
IT Issue

Как работает асинхронность в пайтон?

from random import *
import sys,os,asyncio
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebKit import *
from PyQt5.QtWebKitWidgets import *
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow

port = str(randint(9000, 9999))
url = "http://localhost:"+port
icon = "icon.ico"
title = "Qt Web App"
dw = 1920
dh = 1080
ww = 800
wh = 600

async def run_server():
    os.system("php -S localhost:"+port+" > started.log")

async def run_window():
    app = QApplication(sys.argv)
    web = QWebView()
    web.load(QUrl(url))
    web.setGeometry((dw-ww)/2, (dh-wh)/2, ww, wh)
    web.setWindowTitle(title)
    web.setWindowIcon(QIcon(icon))
    web.show()
    sys.exit(app.exec_())

run_server()
run_window()


В исходном коде есть две функции, одна запускает php сервер, вторая должна отобразить окно для подключения к серверу и просмотра веб приложения. Как я только не игрался с этим asyncio, просто не понимаю как оно должно работать...

Объясните пожалуйста чайнику, как запустить сервер и не ждать от него ничего, но что бы при закрытии программы он тоже завершился?
  • Вопрос задан
  • 357 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 2
Vindicar
@Vindicar
RTFM!
asyncio - это, скорее, как обойтись без многопоточности.
Она хорошо работает для ситуаций, когда большая часть времени потока выполнения уходит на ожидание ввода-вывода - например, на ответ по сети. Если у тебя есть что-то, что занимает CPU, или любая другая операция, выполняемая вне рамок ввода-вывода через asyncio - это остановит выполнение асинхронной программы.
Если на пальцах, то асинхронная программа состоит из отдельных корутин. Разница с потоками в том, что потоки переключает ОС, а корутины сами отдают управление, когда уходят в ожидание события (грубо говоря, когда делают вызов с await). Это упрощает синхронизацию корутин, так как ты точно знаешь, когда твоя корутина отдаст управление - меньше шансов налететь на состояние гонки из-за внезапного переключения. Опять же, переключение корутин куда более детерминировано, чем переключение потоков, так что "плавающие" баги встречаются реже.
Тело асинхронной программы - это рабочий цикл (т.н. реактор, он же loop), который проверяет выполняемые операции ввода-вывода, и возобновляет выполнение корутины, когда её операция завершилась. Когда корутина завершится или запланирует ещё одну операцию, она вернёт управление в цикл. Вот почему "задумавшаяся" корутина остановит всю программу.
Минус в том, что в отличие от многопоточности, нельзя просто вжжжжжжух и сделать код асинхронным. Он должен писаться как асинхронный с самого начала, с прицелом на исполнение в реакторе.
Ответ написан
paulenot
@paulenot Автор вопроса
IT Issue
threading не умеет закрывать потоки, по этому такое решение с этой библиотекой, при закрытии окна запускается функция closer(). Она закрывает pyqt окно а потом читает процессы и убивает процесс php сервера.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from random import *
import sys,os,threading
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebKit import *
from PyQt5.QtWebKitWidgets import *
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow

port = str(randint(9000, 9999))
url = "http://localhost:"+port
comm = "php -S localhost:"+port+" -t app/"
icon = "app/icon.ico"
title = "Qt Web App"
dw = 1920
dh = 1080
ww = 800
wh = 600

def closer():
    app.exec_()
    os.system("ps -ef | grep \""+comm+"\" > .pid ")
    proc = open(".pid")
    proc = proc.readlines()
    for line in proc:
        line = line.split()
        pid = line[1]
        os.system("kill "+pid)
    os.remove('.pid')

def run_server():
    os.system(comm)

server = threading.Thread(target=run_server)
server.start()

app = QApplication(sys.argv)
web = QWebView()
web.load(QUrl(url))
web.setGeometry(int((dw-ww)/2), int((dh-wh)/2), ww, wh)
web.setWindowTitle(title)
web.setWindowIcon(QIcon(icon))
web.show()
sys.exit(closer())
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы