当前位置: 首页 > news >正文

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

在这里插入图片描述


文章目录

  • 前言
    • 为什么要使用多线程
  • 一、单个线程实现按钮方法的执行
  • 二、线程嵌套多个子线程实现按钮方法的执行
  • 三、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 threadingclass MyThread(threading.Thread):def __init__(self, qt):super().__init__()self.qtGui = qtself._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:breaklog_content['five'] = messageself.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 Trueclass 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 = 0self.ui.tableWidgetAnswer.horizontalHeader().setVisible(True)  # 设置tableWidget组件的标题显示为Trueself.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 += 1new_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 Queueclass MyThread(threading.Thread):def __init__(self, qt):super().__init__()self.qtGui = qtself.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:  # 当停止按钮被点击后则会进入这个跳出循环条件breaklog_content['five'] = '答题子线程已停止运行,请进行下一步操作'time.sleep(5)[self.qtGui.logger_show(log_content) for kk in range(1)]return Truedef build_log_messages(self):message_queue = Queue()grapheme_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']num = 0while num < 100:  # 存储需要打印的日志信息for grapheme in grapheme_list:num += 1message_queue.put({'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,'five': f"线程{grapheme} {grapheme * 10} 打印数字:{num}"})return message_queueclass 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 = 0self.ui.tableWidgetAnswer.horizontalHeader().setVisible(True)  # 设置tableWidget组件的标题显示为Trueself.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 += 1new_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 Queuedef 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:continuetime.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 threadingclass 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 threadingclass ThreadWithException(threading.Thread):def __init__(self, _tk, route_number=0):threading.Thread.__init__(self)self._tk = _tkself.route_number = route_numberdef run(self):passdef get_id(self):if hasattr(self, '_thread_id'):return self._thread_idfor id, thread in threading._active.items():if thread is self:return iddef 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 DataSaveclass MyThread(threading.Thread):def __init__(self, qt):super().__init__()self.qtGui = qtself.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:  # 当停止按钮被点击后则会进入这个跳出循环条件breaklog_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 Truedef build_log_messages(self):message_queue = Queue()grapheme_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']num = 0while num < 100:  # 存储需要打印的日志信息for grapheme in grapheme_list:num += 1message_queue.put({'one': '-' * 20, 'two': '-' * 20, 'three': '-' * 20, 'four': '-' * 20,'five': f"线程{grapheme} {grapheme * 10} 打印数字:{num}"})return message_queueclass 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 = 0self.ui.tableWidgetAnswer.horizontalHeader().setVisible(True)  # 设置tableWidget组件的标题显示为Trueself.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 += 1new_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 randomclass DataSave(object):def __init__(self):passdef 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.1time.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/

总结

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

相关文章:

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

文章目录 前言为什么要使用多线程 一、单个线程实现按钮方法的执行二、线程嵌套多个子线程实现按钮方法的执行三、QT GUI常用代码3.1 多线程取出队列任务循环执行&#xff0c;无停止3.2 将某个方法放在线程中执行3.3 QT pyside2 tableWidget 清除日志3.4 退出整个GUI程序(杀死进…...

江西广电会展集团总经理李悦一行莅临拓世科技集团调研参观,科技璀璨AIGC掀新潮

在江西这片充满活力的土地上&#xff0c;数字经济如潮水般涌动&#xff0c;会展文化与科技的完美结合&#xff0c;正如新时代的璀璨繁星照亮夜空&#xff0c;更预示着一场AIGC创新的壮丽篇章即将展开。作为拓世科技集团的老朋友&#xff0c;江西广电多位领导多次莅临拓世科技集…...

【RabbitMQ实战】06 RabbitMQ配置

一、概述 一般情况下&#xff0c;可以使用默认的内建配置来有效地运行RabbitMQ&#xff0c;并且大多数情况下也并不需要修改任何 RabbitMQ的配置。当然&#xff0c;为了更加有效地操控 RabbitMQ&#xff0c;也可以利用调节系统范围内的参数来达到定制化的需求。 RabbitMQ提供…...

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao

文章目录 参考环境题目index.phphighlight_file()include()多次调用&#xff0c;多次执行单次调用&#xff0c;单次执行 $_POST超全局变量HackBarHackBar 插件的获取 $_POST打开 HackBar 插件通过 HackBar 插件发起 POST 请求 GET 请求查询字符串超全局变量 $_GET JSONJSON 数据…...

FL Studio21.1电脑试用体验版音乐制作软件

我一直以来对音乐艺术都很感兴趣。最近我接触到了一款名为 FL Studio 的电脑版音乐制作软件&#xff0c;深感其强大功能和广泛适用性。通过使用这款软件&#xff0c;我不仅深入了解了音乐制作的过程与技巧&#xff0c;也加深了对音乐创作的理解。 FL Studio 最初是一款针对 MI…...

【数据结构】单链表的基本操作(节点建立、插入删除)

1. 单链表的基本操作 1.1. 链表的定义1.2. 链表的创建&#xff08;初始化&#xff09; 1.2.1. 不带头结点的链表1.2.2. 带头结点的链表 1.3. 链表的插入和删除 1.3.1. 按位序插入 1.3.1.1. 带头结点1.3.1.2. 不带头结点 1.3.2. 指定节点的后插操作1.3.3. 指定元素的前插操作1.3…...

DEM格式转换:转换NSDTF-DEM国标数据格式为通用格式,使用ArcGIS工具转换NSDTF-DEM国标.dem文件为通用.tif格式。

DEM格式转换&#xff1a;转换NSDTF-DEM国标数据格式为通用格式&#xff0c;使用ArcGIS工具转换NSDTF-DEM国标.dem文件为通用.tif格式。 *.dem是一种比较常见的DEM数据格式&#xff0c;其有两种文件组织方式&#xff0c;即NSDTF-DEM和USGS-DEM。 &#xff08;1&#xff09;NSDT…...

施耐德电气:勾勒未来工业愿景,赋能中国市场

9月19日&#xff0c;第23届中国国际工业博览会&#xff08;简称“工博会”&#xff09;在上海隆重召开。作为全球能源管理和自动化领域的数字化转型专家&#xff0c;施耐德电气在工博会现场全方位展现了自身对未来工业的全新视野与深刻见解&#xff0c;不仅展示了其贯通企业设计…...

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

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

php中判断指定字符串是否包含指定字符的封装函数

在 PHP 中&#xff0c;你可以使用内置的字符串函数 strpos() 来判断一个字符串是否包含指定的字符或子字符串。以下是一个简单的封装函数&#xff0c;它使用 strpos() 来判断指定字符串是否包含指定字符&#xff0c;并返回一个布尔值。 function stringContains($string, $cha…...

GICI-LIB源码阅读(三)因子图优化模型

原始 Markdown文档、Visio流程图、XMind思维导图见&#xff1a;https://github.com/LiZhengXiao99/Navigation-Learning 文章目录 三、因子图优化&#xff08;FGO&#xff09;1、因子图模型2、因子图优化状态估计模型3、因子图优化求解4、Ceres 非线性最小二乘库5、GICI-LIB 中…...

5、Docker安装mysql主从复制与redis集群

安装mysql主从复制 主从搭建步骤 1.1 新建主服务器容器实例3307 docker run -p 3307:3306 --name mysql-master #3307映射到3306&#xff0c;容器名为mysql-master -v /app/mysql/mydata/mysql-master/log:/var/log/mysql #容器数据卷 -v /app/mysql/mydata/mysql-master/dat…...

【AI视野·今日NLP 自然语言处理论文速览 第四十三期】Thu, 28 Sep 2023

AI视野今日CS.NLP 自然语言处理论文速览 Thu, 28 Sep 2023 Totally 38 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Cross-Modal Multi-Tasking for Speech-to-Text Translation via Hard Parameter Sharing Authors Brian Yan,…...

Unity 制作登录功能01-创建登录的UI并获取输入内容

1.创建UI面板 导入插件TextMesh Pro 2.编写脚本获取用户输入 这里用的是输入框侦听函数&#xff0c;所有UI都可以使用侦听函数 &#xff0c;需要注意TMP_InputField 这个类是UI中导入的一个插件TextMesh Pro&#xff01;在代码中需要引用using TMPro; 命名空间&#xff01; …...

什么是用户画像?

(1&#xff09;首先用户画像是个动词逻辑&#xff0c;不是名词&#xff0c;就是给用户绘制肖像。 (2&#xff09;在互联网这个平台上&#xff0c;绘制肖像就相当千给用户打标签 (3&#xff09;标签通常是人为规定的高度精炼的特征标识&#xff0c;如年龄、性别、地域、兴趣等…...

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

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

基于AIOps实现智慧园区极简IT运维

随着物联网、云平台、大数据、人工智能等技术的发展&#xff0c;并逐步投入到智慧园区的建设&#xff0c;传统园区数字化转型加快。园区的形式包括产业园区、教育园区、制造业园区、科研园区、社区等等&#xff0c;园区形态不断演进和发展&#xff0c;园区网承载的对象和业务也…...

chatgpt 只会死记硬背吗

本周写两篇关于 chatgpt 的随感&#xff0c;我不善于写文档&#xff0c;所以我的文字多是输出直感和观点&#xff0c;而不是知识&#xff0c;没有关于 chatgpt 的原理和应用&#xff0c;甚至术语也不匹配&#xff0c;反正就是想到哪算哪吧。 都说 chatgpt 没有内在逻辑&#xf…...

03-Zookeeper客户端使用

上一篇&#xff1a;02-Zookeeper实战 1. 项目构建 zookeeper 官方的客户端没有和服务端代码分离&#xff0c;他们为同一个jar 文件&#xff0c;所以我们直接引入zookeeper的maven即可&#xff0c; 这里版本请保持与服务端版本一致&#xff0c;不然会有很多兼容性的问题 <…...

自然语言处理(NLP)学习之与HanLP的初相识

目录 前言 一、自然语言处理基本知识 1、NLP类别 2、核心任务 二、Hanlp简要介绍 三、Hanlp云服务能力 1、全新云原生2.x 2、Python api调用 3、Go api调用 4、Java api调用 四、Hanlp native服务 1、本地开发 总结 前言 在ChatGPT的滚滚浪潮下&#xff0c;也伴随着人工智…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...

Spring AOP代理对象生成原理

代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】&#xff0c;这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...

C++--string的模拟实现

一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现&#xff0c;其目的是加强对string的底层了解&#xff0c;以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量&#xff0c;…...

欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!

多连接 BLE 怎么设计服务不会乱&#xff1f;分层思维来救场&#xff01; 作者按&#xff1a; 你是不是也遇到过 BLE 多连接时&#xff0c;调试现场像网吧“掉线风暴”&#xff1f; 温度传感器连上了&#xff0c;心率带丢了&#xff1b;一边 OTA 更新&#xff0c;一边通知卡壳。…...

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)

零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...