[100 días de dominio de Python] Día 38: programación de interfaz GUI_PyQt desde la entrada hasta el combate real (medio) _operación de base de datos y programación multiproceso

Tabla de contenido

  Guía de columna 

4 operaciones de base de datos

4.1 Conectarse a la base de datos

4.2 Ejecutar consultas SQL y actualizaciones:

4.3 Mostrar datos usando modelos y vistas

 5 programación multiproceso

5.1 Conceptos y ventajas de la programación multiproceso

5.2 Usando subprocesos múltiples en PyQt

5.3 Manejo de problemas de sincronización y comunicación entre múltiples subprocesos

5.3.1 Mecanismo de ranura de señal

5.3.2 Acceso a datos seguro para subprocesos

 QMutex y QMutexLocker¶


  Guía de columna 

Dirección de suscripción de columna: https://blog.csdn.net/qq_35831906/category_12375510.html


4 operaciones de base de datos

      

        Las operaciones de bases de datos en PyQt6 involucran principalmente el módulo SQL de Qt, que proporciona funciones para conectar y administrar bases de datos. La siguiente es una descripción general de las operaciones de la base de datos PyQt6:

  1. Conexiones de bases de datos: utilice QSqlDatabaseclases para establecer conexiones a bases de datos. Puede conectarse a varios motores de bases de datos, como SQLite, MySQL, PostgreSQL, etc. La conexión debe especificar el tipo de base de datos, el host, el nombre de usuario, la contraseña y otra información.

  2. Consulta de base de datos: utilice QSqlQueryclases para ejecutar declaraciones de consulta SQL, como SELECT, INSERT, UPDATE, etc. Los resultados de la consulta se pueden obtener mediante iteración.

  3. Arquitectura de vista de modelo: PyQt6 proporciona QSqlTableModelotras QSqlQueryModelclases de modelo para conectar datos de la base de datos con las clases de vista de Qt (como QTableView). Esto facilita la visualización y edición de datos en la base de datos en una vista tabular.

  4. Gestión de transacciones: puede utilizar QSqlDatabase.transaction()y QSqlDatabase.commit()para gestionar las transacciones de la base de datos para garantizar la coherencia e integridad de los datos.

  5. Enlace de datos: mediante bindValue()métodos puede vincular variables a consultas SQL, lo que ayuda a prevenir ataques de inyección SQL.

  6. Manejo de errores: pueden ocurrir errores en las operaciones de la base de datos y se puede obtener información detallada sobre los errores QSqlQuerymarcando .lastError()

4.1 Conectarse a la base de datos

Utilice la clase QSqlDatabase de Qt para conectarse a una base de datos. Aquí hay un ejemplo simple:

from PyQt6.QtSql import QSqlDatabase

db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("my_database.db")
if db.open():
    print("Connected to database")
else:
    print("Failed to connect")

4.2 Ejecutar consultas SQL y actualizaciones:

Puede utilizar la clase QSqlQuery para realizar consultas SQL y operaciones de actualización. Aquí hay un ejemplo:

from PyQt6.QtSql import QSqlQuery

query = QSqlQuery()
query.exec("SELECT * FROM employees")
while query.next():
    name = query.value("name")
    print("Employee name:", name)

4.3 Mostrar datos usando modelos y vistas

        Qt proporciona una arquitectura de vista de modelo para mostrar datos de una base de datos. Por ejemplo, puede utilizar QSqlTableModel para mostrar datos en un QTableView. Aquí hay un ejemplo:

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView, QVBoxLayout, QWidget, QPushButton, QLineEdit, QDockWidget
from PyQt6.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery
from PyQt6.QtCore import Qt

class AddDataDialog(QWidget):
    def __init__(self, model):
        super().__init__()
        self.model = model

        layout = QVBoxLayout()
        self.setLayout(layout)

        # 添加姓名输入框
        self.name_input = QLineEdit(self)
        layout.addWidget(self.name_input)

        # 添加职位输入框
        self.position_input = QLineEdit(self)
        layout.addWidget(self.position_input)

        # 添加 "Add Data" 按钮,并连接到添加数据函数
        add_button = QPushButton("Add Data", self)
        add_button.clicked.connect(self.add_data)
        layout.addWidget(add_button)

    def add_data(self):
        # 获取姓名和职位输入框的内容
        name = self.name_input.text()
        position = self.position_input.text()

        # 准备插入数据的SQL查询
        query = QSqlQuery()
        query.prepare("INSERT INTO employees (name, position) VALUES (?, ?)")
        query.bindValue(0, name)
        query.bindValue(1, position)
        if query.exec():
            print("Data added successfully")
            self.model.select()  # 刷新表格数据
        else:
            print("Error adding data:", query.lastError().text())

def create_database_connection():
    # 创建数据库连接
    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName("employees.db")

    if not db.open():
        print("Error: Could not open database.")
        return None

    return db

def create_table(db):
    # 创建表格的SQL查询
    query = QSqlQuery()
    query.exec("CREATE TABLE IF NOT EXISTS employees (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, position TEXT)")

def setup_model(db):
    # 设置数据库表格模型
    model = QSqlTableModel()
    model.setTable("employees")
    model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)  # 手动提交更改
    model.select()

    return model

if __name__ == "__main__":
    app = QApplication(sys.argv)

    db = create_database_connection()
    if not db:
        sys.exit(1)

    create_table(db)
    model = setup_model(db)

    view = QTableView()
    view.setModel(model)

    add_data_dialog = AddDataDialog(model)

    window = QMainWindow()
    window.setWindowTitle("Database Table Example")
    window.setCentralWidget(view)
    window.setGeometry(100, 100, 800, 600)

    add_data_button = QPushButton("Add Data", window)
    add_data_button.clicked.connect(add_data_dialog.show)

    # 创建 DockWidget 并添加到主窗口的右侧停靠区
    dock_widget = QDockWidget("Add Data", window)
    dock_widget.setWidget(add_data_dialog)
    window.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, dock_widget)

    window.show()

    sys.exit(app.exec())

   

 5 programación multiproceso

5.1 Conceptos y ventajas de la programación multiproceso

        La programación multiproceso en PyQt6 le permite ejecutar múltiples tareas simultáneamente en su aplicación para mejorar el rendimiento, la capacidad de respuesta y la utilización de recursos. Cuando utilice subprocesos múltiples, debe prestar atención a la sincronización y la comunicación entre subprocesos para evitar carreras de datos y otros problemas de concurrencia. La siguiente es una descripción general de la programación multiproceso de PyQt6:

  1. Clase de subproceso (QThread): QThread es la clase base de subproceso proporcionada por PyQt6, que se utiliza para crear y administrar subprocesos. Puede heredar QThreade implementar run()el método para definir la lógica de ejecución del hilo.

  2. Seguridad de subprocesos: en un entorno multiproceso, varios subprocesos pueden acceder y modificar recursos compartidos simultáneamente. Es importante garantizar que el acceso a los recursos compartidos sea seguro para subprocesos y que se QMutexpuedan utilizar mutex ( ) para controlar el acceso a los recursos compartidos.

  3. Mecanismo de señal y ranura: en subprocesos múltiples, generalmente no es posible actualizar la interfaz de usuario directamente en un subproceso no principal. Puede utilizar el mecanismo de señal y ranura para actualizar la interfaz procesando la señal en el hilo principal, evitando así el problema de actualización de la interfaz entre hilos.

  4. Escenarios de aplicación de subprocesos múltiples: el subproceso múltiple es especialmente útil en las siguientes situaciones:

    • Realice operaciones que requieren mucho tiempo, como lectura y escritura de archivos, solicitudes de red, etc., para evitar bloquear el hilo principal.
    • Realice una actualización de datos en tiempo real, como datos de sensores, datos de gráficos, etc.
    • Procese múltiples tareas simultáneamente para mejorar el rendimiento general del programa.
  5. Sincronización y comunicación de subprocesos: la programación multiproceso debe considerar la sincronización y la comunicación entre subprocesos. Los mecanismos de sincronización apropiados (como mutex, semáforos, variables de condición, etc.) y mecanismos de comunicación (como colas, ranuras de señal, etc.) pueden garantizar la cooperación correcta entre subprocesos.

  6. Evite el punto muerto y la falta de subprocesos: el punto muerto y la falta de subprocesos son problemas comunes en la programación multiproceso. Asegúrese de diseñar y organizar correctamente la sincronización y comunicación de subprocesos para evitar estos problemas.

En resumen, la programación multiproceso puede mejorar significativamente el rendimiento y la capacidad de respuesta de su aplicación, pero también requiere una cuidadosa consideración de la seguridad de los subprocesos y los mecanismos de sincronización adecuados. PyQt6 proporciona algunas clases y herramientas para ayudarle a implementar aplicaciones multiproceso, pero los posibles problemas de concurrencia deben manejarse con cuidado.

5.2 Usando subprocesos múltiples en PyQt

        En PyQt, puede utilizar la clase QThread para crear y administrar subprocesos. A continuación se muestra un ejemplo que muestra cómo ejecutar una tarea que requiere mucho tiempo en un hilo:

from PyQt6.QtCore import QThread, pyqtSignal

class WorkerThread(QThread):
    result_ready = pyqtSignal(str)

    def run(self):
        # 执行耗时任务
        result = "Task result"
        self.result_ready.emit(result)

thread = WorkerThread()
thread.result_ready.connect(lambda result: print("Result:", result))
thread.start()

5.3 Manejo de problemas de sincronización y comunicación entre múltiples subprocesos

        En la programación multiproceso, es fundamental abordar los problemas de sincronización y comunicación entre subprocesos para garantizar la coherencia de los datos y la estabilidad de la aplicación. PyQt proporciona varios mecanismos para ayudar con estos problemas, los más importantes de los cuales son el mecanismo de ranuras de señales y el acceso a datos seguro para subprocesos.

5.3.1 Mecanismo de ranura de señal

        El mecanismo de ranura de señal es una herramienta importante en PyQt para la comunicación entre subprocesos. Permite que un objeto (el remitente de la señal) emita una señal y otro objeto (el receptor de la función de ranura) conecte la señal a la función de ranura para realizar la acción correspondiente cuando se dispara la señal. Esto es especialmente útil en un entorno de subprocesos múltiples, ya que evita el intercambio directo de datos entre subprocesos.

El siguiente es un ejemplo sencillo que demuestra cómo utilizar el mecanismo de ranura de señal en subprocesos múltiples:

import sys
from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton

class WorkerThread(QThread):
    result_ready = pyqtSignal(str)

    def run(self):
        result = "Task result"
        self.result_ready.emit(result)

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Thread Communication Example")
        self.setGeometry(100, 100, 400, 300)

        self.button = QPushButton("Start Task", self)
        self.button.setGeometry(150, 150, 100, 30)
        self.button.clicked.connect(self.start_thread)

    def start_thread(self):
        self.thread = WorkerThread()
        self.thread.result_ready.connect(self.handle_result)
        self.thread.start()

    def handle_result(self, result):
        print("Result:", result)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

  

5.3.2 Acceso a datos seguro para subprocesos

        Es probable que se produzcan condiciones de carrera e inconsistencias de datos cuando varios subprocesos acceden a datos compartidos al mismo tiempo. Para evitar estos problemas, es necesario utilizar bloqueos de exclusión mutua (mutex) para proteger el acceso a los datos compartidos. QMutex y QMutexLocker en PyQt pueden ayudarlo a lograr un acceso a datos seguro para subprocesos.

A continuación se muestra un ejemplo sencillo que muestra cómo acceder de forma segura a datos compartidos en varios subprocesos:

import sys
from PyQt6.QtCore import QThread, QMutex, QMutexLocker

class SharedData:
    def __init__(self):
        self.mutex = QMutex()  # 用于保护共享数据的互斥锁
        self.data = 0

    def increment(self):
        locker = QMutexLocker(self.mutex)  # 加锁
        self.data += 1

class WorkerThread(QThread):
    def __init__(self, shared_data):
        super().__init__()
        self.shared_data = shared_data

    def run(self):
        for _ in range(10):
            self.shared_data.increment()

if __name__ == "__main__":
    shared_data = SharedData()  # 创建共享数据对象
    threads = [WorkerThread(shared_data) for _ in range(4)]  # 创建多个工作线程

    for thread in threads:
        thread.start()  # 启动工作线程

    for thread in threads:
        thread.wait()  # 等待所有工作线程完成

    print("Shared data:", shared_data.data)  # 打印最终共享数据的值

producción: 

         En este ejemplo, cada subproceso de trabajo realiza 10 incrementos en un bucle, utilizando un mutex para garantizar que solo un subproceso pueda acceder y modificar las propiedades SharedDatadel objeto dataen cualquier momento. Esto evita carreras de datos e inconsistencias.

        Tenga en cuenta que este ejemplo utiliza subprocesos múltiples y mutex en Python, que son ligeramente diferentes de los subprocesos y mutex en Qt. PyQt6.QtCoreAsegúrese de que tanto la biblioteca Qt como el soporte de subprocesos de Python (por ejemplo , una biblioteca) existan en su entorno threadingpara que el código pueda ejecutarse correctamente.

5.4  Evitar interbloqueos y falta de subprocesos

        Evitar el punto muerto y la falta de subprocesos es una cuestión clave en la programación multiproceso. El punto muerto se refiere a varios subprocesos que esperan entre sí para liberar el bloqueo, lo que impide que el programa continúe ejecutándose. La falta de subprocesos significa que un subproceso no puede obtener los recursos requeridos o se bloquea durante mucho tiempo, lo que hace que otros subprocesos ocupen recursos y el subproceso no pueda continuar ejecutándose. Las siguientes son explicaciones detalladas y ejemplos de cómo evitar interbloqueos y falta de subprocesos en PyQt6:

Evite los puntos muertos:

  1. Adquisición de bloqueos ordenados: cuando varios subprocesos necesitan adquirir varios bloqueos, asegúrese de que los adquieran en el mismo orden, lo que puede reducir el riesgo de interbloqueo.

  2. Mecanismo de tiempo de espera: utilice un mecanismo de tiempo de espera al adquirir un candado. Si el candado no se puede adquirir dentro de un cierto período de tiempo, abandone y libere el candado existente.

Evite la falta de hilo:

  1. Equidad: utilice bloqueos justos y estrategias de asignación de recursos para garantizar que todos los subprocesos tengan las mismas oportunidades de obtener recursos y evitar que un subproceso no pueda obtener los recursos necesarios durante mucho tiempo.

  2. Prioridad: en algunos casos, puede establecer diferentes prioridades para los subprocesos para garantizar que los subprocesos de alta prioridad no puedan obtener recursos durante mucho tiempo.

Aquí hay un ejemplo simple que muestra cómo usar QMutex en PyQt6 para evitar interbloqueos y falta de subprocesos:

import sys
from PyQt6.QtCore import QThread, QMutex, QMutexLocker

# 共享资源类,用于展示互斥锁的使用来避免死锁和线程饥饿
class SharedResource:
    def __init__(self):
        self.mutex1 = QMutex()  # 第一个互斥锁
        self.mutex2 = QMutex()  # 第二个互斥锁

    def process1(self):
        with QMutexLocker(self.mutex1):  # 获取第一个锁
            print("Process 1: Mutex 1 locked")
            QThread.msleep(100)  # 模拟处理时间
            with QMutexLocker(self.mutex2):  # 获取第二个锁
                print("Process 1: Mutex 2 locked")

    def process2(self):
        with QMutexLocker(self.mutex2):  # 获取第二个锁
            print("Process 2: Mutex 2 locked")
            QThread.msleep(100)  # 模拟处理时间
            with QMutexLocker(self.mutex1):  # 获取第一个锁
                print("Process 2: Mutex 1 locked")

class WorkerThread(QThread):
    def __init__(self, shared_resource, process_func):
        super().__init__()
        self.shared_resource = shared_resource
        self.process_func = process_func

    def run(self):
        self.process_func()

if __name__ == "__main__":
    shared_resource = SharedResource()

    thread1 = WorkerThread(shared_resource, shared_resource.process1)
    thread2 = WorkerThread(shared_resource, shared_resource.process2)

    thread1.start()  # 启动线程1
    thread2.start()  # 启动线程2

    thread1.wait()  # 等待线程1完成
    thread2.wait()  # 等待线程2完成

    print("Main thread exited")  # 主线程退出

         En este ejemplo, dos subprocesos intentan adquirir dos bloqueos diferentes (mutex1 y mutex2). Los interbloqueos se evitan adquiriendo siempre los bloqueos en el mismo orden. Al mismo tiempo, al utilizar QMutexLocker al adquirir el bloqueo, puede asegurarse de que el hilo libere el bloqueo cuando salga del alcance.

        Cabe señalar que el punto muerto y la falta de subprocesos son problemas complejos que pueden surgir en escenarios más complejos. Evitar el estancamiento y la falta de subprocesos requiere un diseño y pruebas cuidadosos para garantizar que los subprocesos estén sincronizados y coordinados adecuadamente cuando trabajan juntos.

 QMutexyQMutexLocker

QMutexy QMutexLockerson dos clases importantes para la sincronización de subprocesos en PyQt. Ayudan a garantizar la sincronización adecuada de múltiples subprocesos que acceden a recursos compartidos para evitar condiciones de carrera e inconsistencias de datos. Aquí tienes explicaciones y ejemplos sobre ellos:

QMutex (bloqueo de exclusión mutua): un bloqueo de exclusión mutua es un mecanismo de sincronización de subprocesos que se utiliza para controlar el acceso a recursos compartidos por parte de múltiples subprocesos. En un entorno multiproceso, un subproceso puede tomar posesión de un mutex, lo que permite un acceso seguro a un recurso compartido. Otros subprocesos deben esperar antes de adquirir el mutex para garantizar que solo un subproceso pueda acceder al recurso compartido a la vez.

Código de muestra:

from PyQt6.QtCore import QMutex

mutex = QMutex()

def thread_function():
    mutex.lock()
    # 访问共享资源
    mutex.unlock()

# 创建多个线程,每个线程执行 thread_function

QMutexLocker (casillero de exclusión mutua): QMutexLocker es QMutexuna clase auxiliar de, se bloquea automáticamente cuando se crea QMutexy libera el bloqueo cuando se destruye. Esto puede garantizar que, dentro de un alcance, el subproceso pueda liberar correctamente el bloqueo después de adquirirlo, evitando así el punto muerto causado por olvidarse de liberar el bloqueo.

Código de muestra:

from PyQt6.QtCore import QMutex, QMutexLocker

mutex = QMutex()

def thread_function():
    with QMutexLocker(mutex):  # 进入作用域时自动锁定,离开作用域时自动释放
        # 访问共享资源

# 创建多个线程,每个线程执行 thread_function

        Cuando se usa QMutexLocker, el bloqueo se libera automáticamente cuando el hilo sale del alcance (por ejemplo, usando withla declaración), independientemente de si ocurre una excepción.

Supongo que te gusta

Origin blog.csdn.net/qq_35831906/article/details/132325246
Recomendado
Clasificación