QT pyside2 线程嵌套子线程 实现开始运行和停止运行

news2024/12/30 2:40:03

在这里插入图片描述


文章目录

  • 前言
    • 为什么要使用多线程
  • 一、单个线程实现按钮方法的执行
  • 二、线程嵌套多个子线程实现按钮方法的执行
  • 三、QT GUI常用代码
    • 3.1 多线程取出队列任务循环执行,无停止
    • 3.2 将某个方法放在线程中执行
    • 3.3 QT pyside2 tableWidget 清除日志
    • 3.4 退出整个GUI程序(杀死进程)
    • 3.5 子线程执行和子线程停止
    • 3.6 抛出异常来停止子线程的执行
    • 3.7 使用多个子线程往同一个queue队列对象中存储数据
  • 四、资源推荐
  • 总结


前言

为什么要使用多线程

QT是一种流行的跨平台应用程序开发框架,而PySide2是QT的一个Python绑定库。在QT和PySide2中使用多线程的主要原因是为了提高应用程序的性能和响应能力。

使用多线程可以将耗时的任务分配给不同的线程,在后台并行执行,从而避免阻塞主线程,保持应用程序的流畅性和响应性。当应用程序需要进行复杂的计算、网络请求、文件读写或其他需要较长时间的操作时,使用多线程可以防止这些操作对用户界面的阻塞,使用户能够继续与应用程序进行交互。

需要注意的是在使用多线程时要注意线程安全性和数据同步的问题。多个线程同时访问共享的数据可能导致竞态条件和数据不一致的问题,因此需要采取适当的同步机制,如锁、信号量或其他线程间通信机制,来保证数据的一致性和正确性。

总而言之,使用多线程可以提高QT PySide2应用程序的性能、响应能力和并发性,但需要注意线程安全和数据同步的问题。


提示:以下是本篇文章正文内容,下面案例可供参考

一、单个线程实现按钮方法的执行

实现效果:界面不会卡顿、可以继续与应用程序进行交互;
开始执行、停止执行思路

  • 当点击开始按钮时,分配一个线程a去循环执行按钮绑定的方法,如果变量_stop_event的值为True则一直执行方法;
  • 当点击停止按钮时,分配一个线程b去设置变量_stop_event的值为False,当线程a再次判断时则会跳出执行方法的循环;
  • 具体的逻辑得分析一下MyThread类的代码;
import sys
from PySide2.QtWidgets import QApplication, QWidget, QTableWidgetItem
from PySide2.QtUiTools import loadUiType, QUiLoader
from PySide2.QtCore import QFile, Qt
from PySide2.QtGui import QIcon
import time
import threading


class MyThread(threading.Thread):
    def __init__(self, qt):
        super().__init__()
        self.qtGui = qt
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def run(self):
        message_list = [f"第{k}次打印" for k in range(100)]
        log_content = {'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20}
        for message in message_list:
            if self._stop_event.is_set() is True:
                break
            log_content['five'] = message
            self.qtGui.logger_show(log_content)
            time.sleep(0.1)
        log_content['five'] = '答题子线程已停止运行,请进行下一步操作'
        time.sleep(5)
        [self.qtGui.logger_show(log_content) for kk in range(1)]
        return True


class Gui(QWidget):
    def __init__(self):
        # 加载ui文件,创建qt文件对象,加载文件对象并创建ui对象
        QtFileObj = QFile("yk.ui")
        QtFileObj.open(QFile.ReadOnly)
        QtFileObj.close()
        self.ui = QUiLoader().load(QtFileObj)

        # 设置界面图标
        icon = QIcon("yk.ico")
        self.ui.setWindowIcon(icon)

        # 变量、对象定义
        self.index = 0
        self.ui.tableWidgetAnswer.horizontalHeader().setVisible(True)  # 设置tableWidget组件的标题显示为True
        self.ui.startButton.clicked.connect(self.start_running)  # 绑定按钮的方法
        self.ui.stopButton.clicked.connect(self.stop_running)

        self.answer_thread = None  # 答题启动线程对象

    def start_running(self):
        # 插入内容
        logger_item = {
            'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
            'five': '程序已经开始运行,请勿多次点击开始运行按钮'
        }
        [self.logger_show(logger_item) for kk in range(1)]
        # 创建线程对象
        self.answer_thread = MyThread(self)  # 传入qt对象
        # 启动线程
        self.answer_thread.start()

    def stop_running(self):
        # 停止线程
        self.answer_thread.stop()
        logger_item = {
            'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
            'five': '答题程序已设置停止线程,请等待最后一个账号运行完再进行下一步操作'
        }
        [self.logger_show(logger_item) for kk in range(1)]

    def logger_show(self, logger_item):
        self.ui.tableWidgetAnswer.insertRow(int(self.ui.tableWidgetAnswer.rowCount()))
        self.index += 1
        new_item_one = QTableWidgetItem(logger_item['one'])
        new_item_one.setTextAlignment(Qt.AlignCenter)
        new_item_two = QTableWidgetItem(logger_item['two'])
        new_item_two.setTextAlignment(Qt.AlignCenter)
        new_item_three = QTableWidgetItem(logger_item['three'])
        new_item_three.setTextAlignment(Qt.AlignCenter)
        new_item_four = QTableWidgetItem(logger_item['four'])
        new_item_four.setTextAlignment(Qt.AlignCenter)
        new_item_five = QTableWidgetItem(logger_item['five'])
        new_item_five.setTextAlignment(Qt.AlignCenter)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 0, new_item_one)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 1, new_item_two)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 2, new_item_three)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 3, new_item_four)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 4, new_item_five)
        # 定位至最新行
        self.ui.tableWidgetAnswer.verticalScrollBar().setSliderPosition(self.index)
        # 刷新
        QApplication.processEvents()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ykGuiObj = Gui()
    ykGuiObj.ui.show()
    sys.exit(app.exec_())

二、线程嵌套多个子线程实现按钮方法的执行

实现效果:界面不会卡顿、可以继续与应用程序进行交互,多个子线程同时执行或停止;
开始执行、停止执行思路

  • 当点击开始按钮时,分配一个线程a去开启5个子线程去执行打印日志的方法;
  • 当点击停止按钮时,分配一个线程b去设置变量_stop_event的值为True,当线程a再次判断时则会跳出执行方法的循环;
  • 具体的逻辑得分析一下MyThread类的代码;
  • 可分析运行效果图标红处,同时开了5个子线程去打印,并实现了停止子线程的执行;
import sys
import time
import random
from PySide2.QtWidgets import QApplication, QWidget, QTableWidgetItem
from PySide2.QtUiTools import loadUiType, QUiLoader
from PySide2.QtCore import QFile, Qt
from PySide2.QtGui import QIcon
import threading
import concurrent.futures
from queue import Queue


class MyThread(threading.Thread):
    def __init__(self, qt):
        super().__init__()
        self.qtGui = qt
        self.executor = None  # 创建线程池
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def run(self):
        log_content = {'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20}
        message_queue = self.build_log_messages()
        thread_number = 5  # 线程数
        while message_queue.qsize():
            if self.executor is None or self.executor._shutdown:
                # 创建线程池
                self.executor = concurrent.futures.ThreadPoolExecutor()
            for kkk in range(thread_number):  # 开启4子线程执行打印方法
                self.executor.submit(self.qtGui.logger_show, message_queue.get(), random.randint(1, 15) * 0.1)
                time.sleep(0.2)
            self.executor.shutdown(wait=True)  # 等待任务执行完成
            if self._stop_event.is_set() is True:  # 当停止按钮被点击后则会进入这个跳出循环条件
                break
        log_content['five'] = '答题子线程已停止运行,请进行下一步操作'
        time.sleep(5)
        [self.qtGui.logger_show(log_content) for kk in range(1)]
        return True

    def build_log_messages(self):
        message_queue = Queue()
        grapheme_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
        num = 0
        while num < 100:  # 存储需要打印的日志信息
            for grapheme in grapheme_list:
                num += 1
                message_queue.put(
                    {'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
                     'five': f"线程{grapheme} {grapheme * 10} 打印数字:{num}"}
                )
        return message_queue


class Gui(QWidget):
    def __init__(self):
        # 加载ui文件,创建qt文件对象,加载文件对象并创建ui对象
        QtFileObj = QFile("yk.ui")
        QtFileObj.open(QFile.ReadOnly)
        QtFileObj.close()
        self.ui = QUiLoader().load(QtFileObj)

        # 设置界面图标
        icon = QIcon("yk.ico")
        self.ui.setWindowIcon(icon)

        # 变量、对象定义
        self.index = 0
        self.ui.tableWidgetAnswer.horizontalHeader().setVisible(True)  # 设置tableWidget组件的标题显示为True
        self.ui.startButton.clicked.connect(self.start_running)  # 绑定按钮的方法
        self.ui.stopButton.clicked.connect(self.stop_running)

        self.answer_thread = None  # 答题启动线程对象

    def start_running(self):
        # 插入内容
        logger_item = {
            'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
            'five': '程序已经开始运行,请勿多次点击开始运行按钮'
        }
        [self.logger_show(logger_item) for kk in range(1)]
        # 创建线程对象
        self.answer_thread = MyThread(self)  # 传入qt对象
        # 启动线程
        self.answer_thread.start()

    def stop_running(self):
        # 停止线程
        self.answer_thread.stop()
        logger_item = {
            'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
            'five': '答题程序已设置停止线程,请等待最后一个账号运行完再进行下一步操作'
        }
        [self.logger_show(logger_item) for kk in range(1)]

    def logger_show(self, logger_item, sleep=0):
        time.sleep(sleep)
        self.ui.tableWidgetAnswer.insertRow(int(self.ui.tableWidgetAnswer.rowCount()))
        self.index += 1
        new_item_one = QTableWidgetItem(logger_item['one'])
        new_item_one.setTextAlignment(Qt.AlignCenter)
        new_item_two = QTableWidgetItem(logger_item['two'])
        new_item_two.setTextAlignment(Qt.AlignCenter)
        new_item_three = QTableWidgetItem(logger_item['three'])
        new_item_three.setTextAlignment(Qt.AlignCenter)
        new_item_four = QTableWidgetItem(logger_item['four'])
        new_item_four.setTextAlignment(Qt.AlignCenter)
        new_item_five = QTableWidgetItem(logger_item['five'])
        new_item_five.setTextAlignment(Qt.AlignCenter)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 0, new_item_one)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 1, new_item_two)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 2, new_item_three)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 3, new_item_four)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 4, new_item_five)
        # 定位至最新行
        self.ui.tableWidgetAnswer.verticalScrollBar().setSliderPosition(self.index)
        # 刷新
        QApplication.processEvents()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ykGuiObj = Gui()
    ykGuiObj.ui.show()
    sys.exit(app.exec_())

在这里插入图片描述

三、QT GUI常用代码

3.1 多线程取出队列任务循环执行,无停止

import time
import threading
from queue import Queue


def task_running(param1, param2):
    while True:
        task_info = task_queue.get()  # 取出任务
        time.sleep(1)
        print(task_info)
        task_queue.task_done()  # 全部完成则退出死循环
    
    
def thread_controller(task_queue):
    thread_number = 3  # 线程数
    for j in range(thread_number):
        t = threading.Thread(target=task_running, args=(1, 2))
        t.daemon = True  # 设置线程daemon 主线程退出就直接让子线程跟随退出
        t.start()
        

if __name__ == '__main__':
    task_queue = Queue()
    thread_controller(task_queue)

3.2 将某个方法放在线程中执行

# 调用示例
StartButton.clicked.connect(lambda: self.thread_it(self.function, param))

def thread_it(self, func, *args):
    '''
        将函数打包进线程
    '''
    self.myThread = threading.Thread(target=func, args=args)
    self.myThread.setDaemon(True)
    self.myThread.start()

3.3 QT pyside2 tableWidget 清除日志

def clear_logger(self, route_name=None):
    for i in range(self.index):
        self.tableWidget .removeRow(0)  # 删除tableWidget组件的第0行数据
        # self.ui.tableWidget.clearContents()  # 清除/删除所有内容
        time.sleep(1)
    self.index = 0

3.4 退出整个GUI程序(杀死进程)

def exit_program(self, route_name):
    tmp = os.popen("tasklist").readlines()
    for tm in tmp:
    	if 'python' not in tm:
    		continue
    	time.sleep(0.5)
        pid = tm.strip().replace(' ', '').split('.exe')[-1].split('Console')[0]
        subprocess.Popen("taskkill /F /T /PID " + str(pid), shell=True)
    return True

3.5 子线程执行和子线程停止

import threading


class MyThread(threading.Thread):
    def __init__(self, qt):
        super().__init__()
        self._stop_event = threading.Event()
    
    def stop(self):
        self._stop_event.set()

    def run(self):
        while True:
            print("开始运行")
            if self._stop_event.is_set() is True:  # 当停止按钮被点击后则会进入这个跳出循环条件
                break

3.6 抛出异常来停止子线程的执行

import ctypes
import threading


class ThreadWithException(threading.Thread):
    def __init__(self, _tk, route_number=0):
        threading.Thread.__init__(self)
        self._tk = _tk
        self.route_number = route_number

    def run(self):
        pass
    
    def get_id(self):
        if hasattr(self, '_thread_id'):
            return self._thread_id
        for id, thread in threading._active.items():
            if thread is self:
                return id
    
    def raise_exception(self):
        thread_id = self.get_id()
        # 精髓就是这句话,给线程发过去一个exceptions,线程就那边响应完就停了
        response = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
        if response > 1:
            ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)

3.7 使用多个子线程往同一个queue队列对象中存储数据

逻辑解释

  • queue模块提供了线程安全的队列类Queue,可以安全地在多个线程之间进行数据存储和获取操作;
  • 在主进程中创建一个queue对象,调用方法开启多子线程时将queue对象作为参数传入;
  • 多个子线程可以通过queue对象进行数据存储,并且不会发生数据冲突的情况;
  • 主进程也可开启一个子线程去实时监听queue对象中是否有新的数据存入,如果有则进行处理;
  • 下面我分了两个源码文件进行演示,一个是gui.py主要写的是qt代码,另一个是data_save.py主要是进行数据存储的代码;
gui.py
import sys
import time
import random
from PySide2.QtWidgets import QApplication, QWidget, QTableWidgetItem
from PySide2.QtUiTools import loadUiType, QUiLoader
from PySide2.QtCore import QFile, Qt
from PySide2.QtGui import QIcon
import threading
import concurrent.futures
from queue import Queue
from data_save import DataSave


class MyThread(threading.Thread):
    def __init__(self, qt):
        super().__init__()
        self.qtGui = qt
        self.executor = None  # 创建线程池
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def run(self):
        task_queue = Queue()
        log_content = {'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20}
        message_queue = self.build_log_messages()
        thread_number = 5  # 线程数
        while message_queue.qsize():
            if self.executor is None or self.executor._shutdown:
                # 创建线程池
                self.executor = concurrent.futures.ThreadPoolExecutor()
            for kkk in range(thread_number):  # 开启5子线程执行打印方法
                data_sava_pipeline = DataSave()
                self.executor.submit(data_sava_pipeline.runs, self.qtGui, task_queue, message_queue.get())
                time.sleep(0.2)
            self.executor.shutdown(wait=True)  # 等待任务执行完成
            if self._stop_event.is_set() is True:  # 当停止按钮被点击后则会进入这个跳出循环条件
                break
        log_content['five'] = '答题子线程已停止运行,请进行下一步操作'
        print('task_queue', task_queue.qsize(), task_queue.queue)
        time.sleep(2)
        [self.qtGui.logger_show(log_content) for kk in range(1)]
        return True

    def build_log_messages(self):
        message_queue = Queue()
        grapheme_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
        num = 0
        while num < 100:  # 存储需要打印的日志信息
            for grapheme in grapheme_list:
                num += 1
                message_queue.put(
                    {'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
                     'five': f"线程{grapheme} {grapheme * 10} 打印数字:{num}"}
                )
        return message_queue


class Gui(QWidget):
    def __init__(self):
        # 加载ui文件,创建qt文件对象,加载文件对象并创建ui对象
        QtFileObj = QFile("D:\MyStudy\MyProject\PythonProject\python_example\项目接单学习/18_PYQT\可视化编程\yk.ui")
        QtFileObj.open(QFile.ReadOnly)
        QtFileObj.close()
        self.ui = QUiLoader().load(QtFileObj)

        # 设置界面图标
        icon = QIcon("yk.ico")
        self.ui.setWindowIcon(icon)

        # 变量、对象定义
        self.index = 0
        self.ui.tableWidgetAnswer.horizontalHeader().setVisible(True)  # 设置tableWidget组件的标题显示为True
        self.ui.startButton.clicked.connect(self.start_running)  # 绑定按钮的方法
        self.ui.stopButton.clicked.connect(self.stop_running)

        self.answer_thread = None  # 答题启动线程对象

    def start_running(self):
        # 插入内容
        logger_item = {
            'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
            'five': '程序已经开始运行,请勿多次点击开始运行按钮'
        }
        [self.logger_show(logger_item) for kk in range(1)]
        # 创建线程对象
        self.answer_thread = MyThread(self)  # 传入qt对象
        # 启动线程
        self.answer_thread.start()

    def stop_running(self):
        # 停止线程
        self.answer_thread.stop()
        logger_item = {
            'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,
            'five': '答题程序已设置停止线程,请等待最后一个账号运行完再进行下一步操作'
        }
        [self.logger_show(logger_item) for kk in range(1)]

    def logger_show(self, logger_item, sleep=0):
        time.sleep(sleep)
        self.ui.tableWidgetAnswer.insertRow(int(self.ui.tableWidgetAnswer.rowCount()))
        self.index += 1
        new_item_one = QTableWidgetItem(logger_item['one'])
        new_item_one.setTextAlignment(Qt.AlignCenter)
        new_item_two = QTableWidgetItem(logger_item['two'])
        new_item_two.setTextAlignment(Qt.AlignCenter)
        new_item_three = QTableWidgetItem(logger_item['three'])
        new_item_three.setTextAlignment(Qt.AlignCenter)
        new_item_four = QTableWidgetItem(logger_item['four'])
        new_item_four.setTextAlignment(Qt.AlignCenter)
        new_item_five = QTableWidgetItem(logger_item['five'])
        new_item_five.setTextAlignment(Qt.AlignCenter)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 0, new_item_one)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 1, new_item_two)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 2, new_item_three)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 3, new_item_four)
        self.ui.tableWidgetAnswer.setItem(self.index - 1, 4, new_item_five)
        # 定位至最新行
        self.ui.tableWidgetAnswer.verticalScrollBar().setSliderPosition(self.index)
        # 刷新
        QApplication.processEvents()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ykGuiObj = Gui()
    ykGuiObj.ui.show()
    sys.exit(app.exec_())
data_save.py
import time
import random


class DataSave(object):
    def __init__(self):
        pass

    def data_save(self, items):
        message = items['message']
        items['queue'].put(message)
        items['qt'].logger_show(message)

    def runs(self, qt, queue, message):
        sleep = random.randint(2, 10) * 0.1
        time.sleep(sleep)
        print(f'message:{message} sleep:{sleep}\n', end='')
        items = {'qt': qt, 'queue': queue, 'message': message}
        self.data_save(items)

在这里插入图片描述

四、资源推荐

1、QT Pyside2 Designer 的基本使用:https://blog.csdn.net/EXIxiaozhou/article/details/131401574
2、入门文档请看白月黑羽:https://www.byhy.net/tut/py/gui/qt_01
3、入门视频请看白月黑羽:https://www.bilibili.com/video/BV19A411H7dS/
4、深入学习博主推荐-国内站点:https://gitee.com/feiyangqingyun
5、深入学习博主推荐-国际站点:https://github.com/feiyangqingyun
6、CSDN个人主页:https://blog.csdn.net/feiyangqingyun
7、官网:https://www.pythonguis.com/topics/pyside2/

总结

这篇博文的示例主要以实现功能为目的,我自己觉得有地方不太合适,欢迎大佬和小伙伴在评论处积极提出;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1049918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从入门到精通:详解SVN版本控制系统的使用方法

从入门到精通&#xff1a;详解SVN版本控制系统的使用方法 一、引言1.1、版本控制的概念和重要性1.2、流行的版本控制系统SVN 二、SVN基础知识2.1、SVN的基本概念和术语解释2.2、SVN的工作原理和架构 三、创建SVN仓库3.1、创建本地仓库3.2、配置访问权限 四、使用SVN进行版本控制…

基于AI图像识别的智能缺陷检测系统,在钢铁行业的应用-技术方案

目录 概述 废钢智能检判方案简介 废钢智能检判系统优势及价值 废钢人工检判过程 废钢等级检判标准 废钢检判结果 智能检判方案-废钢智能检判算法 算法一&#xff1a;废钢等级识别算法 算法二&#xff1a;不合格料的位置识别算法 算法三&#xff1a;不合格料的类型识别…

docker-compose 网络配置- IP 主机名 hosts配置

docker-compose 配置IP、hostname、hosts配置 配置IP version: "3" networks:bd-network: # 声明网络external: true services:kafka: # 服务名称networks:bd-network: # 连接的网络名称ipv4_address: 172.2.0.102 # 配置IP配置 主机名 version: "3&quo…

DevExpress WinForms图表组件 - 直观的数据信息呈现方式!(二)

在上文中&#xff08;点击这里回顾>>&#xff09;&#xff0c;我们为大家介绍了DevExpress WinForms图表控件的互动图表、图标设计器及可定制功能等&#xff0c;本文将继续介绍DevExpress WinForms图表控件的数据分析、大数据功能等&#xff0c;欢迎持续关注我们哦~ Dev…

数据结构与算法——17.二叉搜索树

这篇文章我们来看一下数据结构中的二叉搜索树。 目录 1.概述 2.二叉搜索树的实现 3.总结 1.概述 我们前面学到的数据结构&#xff0c;比如&#xff1a;动态数组、链表、队列、栈、堆&#xff0c;这些数据结构存储完数据后&#xff0c;我们要去查找某个数据&#xff0c;它的…

FPGA 多路视频处理:图像缩放+视频拼接显示,HDMI采集,提供2套工程源码和技术支持

目录 1、前言版本更新说明免责声明 2、相关方案推荐FPGA图像缩放方案推荐FPGA视频拼接方案推荐 3、设计思路框架视频源选择IT6802解码芯片配置及采集动态彩条缓冲FIFO图像缩放模块详解设计框图代码框图2种插值算法的整合与选择 视频拼接算法图像缓存视频输出 4、vivado工程1&am…

PIE:1979-2018年中国气温数据产品(空间分辨率为0.1º)

简介 中国气温数据产品包含1979-2018年期间中国的近地表气温数据&#xff08;单位为摄氏度&#xff09;&#xff0c;时间分辨率为每日&#xff0c;空间分辨率为0.1。本产品集成了再分析数据&#xff08;ERA5、CMFD&#xff09;、遥感数据&#xff08;MODIS&#xff09;、原位数…

RISC-V架构的函数调用规范和栈布局

1、函数调用中寄存器规范 2、函数调用规范 &#xff08;1&#xff09;函数的前8个参数使用a0-a7寄存器传递&#xff0c;如果传参多于8个&#xff0c;则除前8个参数使用寄存器来传递之外&#xff0c;后面的参数使用栈传递&#xff1b; &#xff08;2&#xff09;如果传递的参数小…

《学术小白学习之路10》论文常见方法:Doc2vec-句向量模型实现

1. 数据 用于文献的摘要的相似度的计算 ## 导包 import pandas as pd import jieba import gensim from gensim.models import Doc2Vec from gensim.models.doc2vec import TaggedDocument再定义停用词典,用于分词,还可以自己定义一个分词词典 ## 读入数据 papers = pd.&l…

TensorFlow入门(一、环境搭建)

一、下载安装Anaconda 下载地址:http://www.anaconda.comhttp://www.anaconda.com 下载完成后运行exe进行安装 二、下载cuda 下载地址:http://developer.nvidia.com/cuda-downloadshttp://developer.nvidia.com/cuda-downloads 下载完成后运行exe进行安装 安装后winR cmd进…

解密PDF密码

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密&#xff1f; PDF和office一样&#xff0c;可以对文件进行加密&#xff0c;但是没有提供恢复密码的功…

解决craco启动react项目卡死在Starting the development server的问题

现象&#xff1a; 原因&#xff1a;craco.config.ts配置文件有问题 经过排查发现Dev开发模式下不能有splitChunk的配置&#xff0c; 解决办法&#xff1a; 加一个生产模式的判断&#xff0c;开发模式不加载splitChunk的配置&#xff0c;仅在生产模式才加载 判断条件代码&#…

基于微信小程的流浪动物领养小程序设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

安防监控产品经营商城小程序的作用是什么

安防监控产品覆盖面较大&#xff0c;监控器、门禁、对讲机、烟感等都有很高用途&#xff0c;家庭、办公单位各场景往往用量不少&#xff0c;对商家来说&#xff0c;市场高需求背景下也带来了众多生意&#xff0c;但线下门店的局限性&#xff0c;导致商家想要进一步增长不容易。…

进阶指针(二)

#国庆发生的那些事儿# ✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;进阶C语言 &#x1f388;推荐相关博文&#xff1a;进阶指针&#xff08;一&#xff09; 进阶指针&#xff08;二&#xff09; 6.函数指针数组6.1例子 7.指向函数指针数组的指针8.…

OpenHarmony自定义组件介绍

一、创建自定义组件 在ArkUI中&#xff0c;UI显示的内容均为组件&#xff0c;由框架直接提供的称为系统组件&#xff0c;由开发者定义的称为自定义组件。在进行 UI 界面开发时&#xff0c;通常不是简单的将系统组件进行组合使用&#xff0c;而是需要考虑代码可复用性、业务逻辑…

四、YApi的安装和配置

YApi是去哪儿网的前端技术中心的一个开源可视化接口管理平台。 创建接口项目 创建接口 编写接口

中文读唇总动员:CNVSRC 2023 视觉语音识别挑战赛启动

由 NCMMSC 2023 组委会发起&#xff0c;清华大学、北京邮电大学、海天瑞声、语音之家共同主办的 CNVSRC 2023 中文连续视觉语音识别挑战赛即日启动&#xff0c;诚邀参与报名。 赛事官网&#xff1a;http://cnceleb.org/competition 视觉语音识别&#xff0c;也称唇语识别&…

为什么我的Windows 10笔记本电脑明明什么软件都没开,风扇却一直在转?

2023年9月29日&#xff0c;周五上午 这两天我的笔记本电脑一开机&#xff0c;风扇就一直在转&#xff0c;而且还没停过&#xff0c;挺吵的 即使什么软件都没开&#xff0c;还在那转&#xff0c;莫名其妙的。 后来我去任务管理器按照CPU使用情况来排序&#xff0c;发现原来是W…

如何自动转发接收的请求报头?

了解OpenTelemetry的朋友应该知道&#xff0c;为了将率属于同一个请求的多个操作&#xff08;Span&#xff09;串起来&#xff0c;上游应用会生成一个唯一的TraceId。在进行跨应用的Web调用时&#xff0c;这个TraceId和代表跟踪操作标识的SpanID一并发给目标应用&#xff0c;W3…