鱼C论坛

 找回密码
 立即注册
查看: 1488|回复: 51

多线程求教~~

[复制链接]
发表于 2024-3-14 18:49:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
请问Pyside6中的多线程用哪个好?  具体要怎么设置?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-3-14 18:49:48 | 显示全部楼层
在Pyside6中,可以使用`QThread`类来实现多线程。以下是一个简单的使用示例:
from PySide6.QtCore import QThread, Signal

# 创建自定义的线程类
class MyThread(QThread):
    # 定义信号,在耗时任务完成后发射信号通知主线程
    finished = Signal()

    def run(self):
        # 在这里编写耗时的任务代码
        # ...
        
        # 任务完成后发射信号
        self.finished.emit()

# 创建线程对象
thread = MyThread()

# 连接信号和槽函数
thread.finished.connect(my_slot)

# 启动线程
thread.start()

在上面的示例中,首先创建了一个继承自`QThread`的自定义线程类`MyThread`。`run()`方法是线程的入口函数,在这里编写了耗时的任务代码。在任务完成后,通过`finished`信号发射出去。

然后,创建了一个线程对象`thread`,并连接了`thread.finished`信号与槽函数`my_slot`。最后,通过`start()`方法启动线程。

需要注意的是,由于PySide6中的GUI操作必须在主线程中进行,因此在耗时任务的代码中不能进行GUI相关的操作。如果需要在耗时任务中更新GUI界面,可以在适当的地方使用信号和槽机制进行通信。

以上是简单的多线程使用示例,如需更复杂的操作,还可以使用`QThreadPool`类来管理多个线程。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 18:49:54 | 显示全部楼层
同问~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-3-14 19:22:31 | 显示全部楼层
FishC 发表于 2024-3-14 18:49
在Pyside6中,可以使用`QThread`类来实现多线程。以下是一个简单的使用示例:

那请问具体在这个例子中要如何设置呢?

Python版本:

Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct  2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32


Pyside6版本:

Name: PySide6
Version: 6.6.2                                                                 
Summary: Python bindings for the Qt cross-platform application and UI framework
Home-page:                                                                     
Author:                                                                        
Author-email: Qt for Python Team <pyside@qt-project.org>                       
License: LGPL                                                                  
Location: D:\Tools\Python\Lib\site-packages                                    
Requires: PySide6-Addons, PySide6-Essentials, shiboken6


请问为什么执行下列红色的for语句就会卡死?  没有任何报错,就是卡半天,然后说程序失去响应。。。。

       def exclude_rows_and_cols(self, exclude_rows_and_cols):
        if self.File_Type == 'xls':
            file_name = "123.xls"
            # 拼接文件路径
            file_path = os.path.join(self.File_Path, file_name)
            Exclud_Book = xlrd.open_workbook(file_path)
        else:
            file_name = "123.xlsx"
            # 拼接文件路径
            file_path = os.path.join(self.File_Path, file_name)
            Exclud_Book = load_workbook(file_path)

        print('《123》共有', len(Exclud_Book.sheet_names()), '个工作表(sheet)。名称分别为:', Exclud_Book.sheet_names())

       for sheet_name in Exclud_Book.sheet_names():
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 19:23:15 | 显示全部楼层
FishC 发表于 2024-3-14 18:49
在Pyside6中,可以使用`QThread`类来实现多线程。以下是一个简单的使用示例:

那请问具体在这个例子中要如何设置呢?

Python版本:

Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct  2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32


Pyside6版本:

Name: PySide6
Version: 6.6.2                                                                 
Summary: Python bindings for the Qt cross-platform application and UI framework
Home-page:                                                                     
Author:                                                                        
Author-email: Qt for Python Team <pyside@qt-project.org>                       
License: LGPL                                                                  
Location: D:\Tools\Python\Lib\site-packages                                    
Requires: PySide6-Addons, PySide6-Essentials, shiboken6


请问为什么执行下列红色的for语句就会卡死?  没有任何报错,就是卡半天,然后说程序失去响应。。。。

       def exclude_rows_and_cols(self, exclude_rows_and_cols):
        if self.File_Type == 'xls':
            file_name = "123.xls"
            # 拼接文件路径
            file_path = os.path.join(self.File_Path, file_name)
            Exclud_Book = xlrd.open_workbook(file_path)
        else:
            file_name = "123.xlsx"
            # 拼接文件路径
            file_path = os.path.join(self.File_Path, file_name)
            Exclud_Book = load_workbook(file_path)

        print('《123》共有', len(Exclud_Book.sheet_names()), '个工作表(sheet)。名称分别为:', Exclud_Book.sheet_names())

       for sheet_name in Exclud_Book.sheet_names():
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 19:23:37 | 显示全部楼层
yxxxzx123 发表于 2024-03-14 19:23
那请问具体在这个例子中要如何设置呢?

Python版本 ...


在你提供的代码中,遍历工作表的循环部分没有给出具体的代码内容,因此很难确定造成程序卡死的具体原因。不过,通常情况下程序卡死的原因可能是因为某个耗时的操作导致主线程被阻塞。

在GUI应用中,主线程负责处理用户界面和响应用户输入,如果在主线程中执行耗时的操作,就会导致界面无法更新和用户无法响应。

为了解决这个问题,可以将耗时的操作放在一个单独的线程中进行,以避免阻塞主线程。可以使用上文中提到的`QThread`类来实现多线程。

以下是一个示例,展示了如何在Pyside6中使用多线程来遍历工作表:
from PySide6.QtCore import QThread, Signal

class MyThread(QThread):
    finished = Signal(list)  # 定义信号,在任务完成后传递工作表名称列表
    
    def __init__(self, file_path):
        super().__init__()
        self.file_path = file_path
        
    def run(self):
        if self.File_Type == 'xls':
            Exclud_Book = xlrd.open_workbook(self.file_path)
        else:
            Exclud_Book = load_workbook(self.file_path)
        
        sheet_names = Exclud_Book.sheet_names()
        self.finished.emit(sheet_names)

# 创建线程对象
thread = MyThread(file_path)
# 连接信号和槽函数
thread.finished.connect(my_slot)
# 启动线程
thread.start()

在这个示例中,创建了一个继承自`QThread`的自定义线程类`MyThread`。在`run()`方法中执行了遍历工作表的耗时操作,并通过定义的信号`finished`传递工作表名称列表。

然后,创建了线程对象`thread`,并连接了`thread.finished`信号与槽函数`my_slot`。最后,通过`start()`方法启动线程。

请将`file_path`替换为你具体需要遍历的文件路径。

注意,在实际使用中,你需要根据具体情况修改代码逻辑以满足你的需求。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 19:46:20 | 显示全部楼层
FishC 发表于 2024-3-14 19:23
在你提供的代码中,遍历工作表的循环部分没有给出具体的代码内容,因此很难确定造成程序卡死的具体原因 ...

我的理解是,把所有任务都并排嵌套在这个 MyThread(QThread)类中,就像下面这样:

from PySide6.QtCore import QThread, Signal

class MyThread(QThread):
    finished = Signal(list)  # 定义信号,在任务完成后传递工作表名称列表
   
    def __init__(self, file_path):
        super().__init__()
        self.file_path = file_path
        
    def run1(self):
        if self.File_Type == 'xls':
            Exclud_Book = xlrd.open_workbook(self.file_path)
        else:
            Exclud_Book = load_workbook(self.file_path)
        
        sheet_names = Exclud_Book.sheet_names()
        self.finished.emit(sheet_names)

def run2(self):....

def run3(self):....

def run4(self):....

# 创建线程对象
thread = MyThread(file_path)
# 连接信号和槽函数
thread.finished.connect(my_slot)
# 启动线程
thread.start()


我这样理解 对吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 19:46:30 | 显示全部楼层
yxxxzx123 发表于 2024-03-14 19:46
我的理解是,把所有任务都并排嵌套在这个 MyThread(QT ...


不完全正确。在上面提供的代码中,你将所有的任务都写在了`MyThread`类中,但是每个线程对象只有一个`run()`方法,而且你在定义方法时出现了`run1()`、`run2()`等多个方法,这会导致语法错误。正确的做法是,在一个`run()`方法中执行所有的任务。以下是修改后的示例代码:from PySide6.QtCore import QThread, Signalclass MyThread(QThread):    finished = Signal(list)  # 定义信号,在任务完成后传递工作表名称列表    def __init__(self, file_path):        super().__init__()        self.file_path = file_path    def run(self):        if self.File_Type == 'xls':            Exclud_Book = xlrd.open_workbook(self.file_path)        else:            Exclud_Book = load_workbook(self.file_path)        sheet_names = Exclud_Book.sheet_names()        self.finished.emit(sheet_names)# 创建线程对象thread = MyThread(file_path)# 连接信号和槽函数thread.finished.connect(my_slot)# 启动线程thread.start()在修改后的代码中,`MyThread`类只有一个`run()`方法,其中包含了遍历工作表的整个任务逻辑。你可以根据实际需求在`run()`方法中添加其他需要执行的任务。另外,注意确保代码中的缩进和命名的准确性。请将`file_path`替换为你具体需要遍历的文件路径。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 20:57:26 | 显示全部楼层
FishC 发表于 2024-3-14 19:46
不完全正确。在上面提供的代码中,你将所有的任务都写在了`MyThread`类中,但是每个线程对象只有一个`r ...

回复请注意python格式
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 20:58:41 | 显示全部楼层
FishC 发表于 2024-3-14 19:46
不完全正确。在上面提供的代码中,你将所有的任务都写在了`MyThread`类中,但是每个线程对象只有一个`r ...

回复请注意python格式
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 21:10:03 | 显示全部楼层
FishC 发表于 2024-3-14 19:46
不完全正确。在上面提供的代码中,你将所有的任务都写在了`MyThread`类中,但是每个线程对象只有一个`r ...

回复请注意python格式啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 21:10:39 | 显示全部楼层
FishC 发表于 2024-3-14 19:46
不完全正确。在上面提供的代码中,你将所有的任务都写在了`MyThread`类中,但是每个线程对象只有一个`r ...

回复请注意python 格式啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 21:11:00 | 显示全部楼层
yxxxzx123 发表于 2024-03-14 21:10
回复请注意python 格式啊


非常抱歉,对于格式的问题给您带来困扰。以下是修改后的代码,采用了正确的Python格式:
from PySide6.QtCore import QThread, Signal

class MyThread(QThread):
    finished = Signal(list)  # 定义信号,在任务完成后传递工作表名称列表
    
    def __init__(self, file_path):
        super().__init__()
        self.file_path = file_path
    
    def run(self):
        if self.File_Type == 'xls':
            Exclud_Book = xlrd.open_workbook(self.file_path)
        else:
            Exclud_Book = load_workbook(self.file_path)
        
        sheet_names = Exclud_Book.sheet_names()
        self.finished.emit(sheet_names)

# 创建线程对象
thread = MyThread(file_path)
# 连接信号和槽函数
thread.finished.connect(my_slot)
# 启动线程
thread.start()

再次对之前的错误表示歉意,并感谢您的指正。希望现在的代码格式更合适了。如有任何其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 21:16:33 | 显示全部楼层
FishC 发表于 2024-3-14 21:11
非常抱歉,对于格式的问题给您带来困扰。以下是修改后的代码,采用了正确的Python格式:

这个我还是没懂。  你 的意思是:一个class MyThread(QThread)只能装一个def?

那像我的好多个按钮(每个按钮又对应好几个操作(比如说其中A按钮就对应着A1打开工作簿,A2遍历簿中的所有sheet ,A3然后把每个sheet中每格的值进行累加),那这多线程要怎么写呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 21:17:02 | 显示全部楼层
yxxxzx123 发表于 2024-03-14 21:16
这个我还是没懂。  你 的意思是:一个class MyThread( ...


非常抱歉之前的回答可能给您带来了一些误解。在一个`class MyThread(QThread)`中,可以定义多个方法来表示不同的操作。对于您的情况,有多个按钮,每个按钮对应多个操作,可以考虑如下的多线程写法:
from PySide6.QtCore import QThread, Signal

# 创建自定义的线程类
class MyThread(QThread):
    # 定义信号,在每个操作完成后发射信号通知主线程
    operation_finished = Signal(str)
    
    def __init__(self, button_name):
        super().__init__()
        self.button_name = button_name
    
    def run(self):
        if self.button_name == "A":
            self.operation_A1()
            self.operation_A2()
            self.operation_A3()
            self.operation_finished.emit("A finished")
        elif self.button_name == "B":
            self.operation_B1()
            self.operation_B2()
            self.operation_finished.emit("B finished")
        # 添加其他按钮对应的操作
        
    def operation_A1(self):
        # A1的操作代码
        
    def operation_A2(self):
        # A2的操作代码
        
    def operation_A3(self):
        # A3的操作代码
        
    def operation_B1(self):
        # B1的操作代码
        
    def operation_B2(self):
        # B2的操作代码

# 创建线程对象
thread_A = MyThread("A")
thread_B = MyThread("B")

# 连接信号和槽函数
thread_A.operation_finished.connect(my_slot_A)
thread_B.operation_finished.connect(my_slot_B)

# 启动线程
thread_A.start()
thread_B.start()

在上面的示例中,首先定义了一个继承自`QThread`的自定义线程类`MyThread`。在`run()`方法中,根据按钮的名称来执行对应的操作。每个操作都是一个独立的方法,可以根据实际需求添加和修改。通过`operation_finished`信号发射一个字符串来通知主线程该操作已完成。然后,创建了两个线程对象`thread_A`和`thread_B`,分别对应两个按钮。将每个线程的操作完成信号与相关的槽函数连接起来。最后,通过`start()`方法启动线程。

希望这次的回答能够更好地解决您的问题。如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 21:23:04 | 显示全部楼层
FishC 发表于 2024-3-14 21:17
非常抱歉之前的回答可能给您带来了一些误解。在一个`class MyThread(QThread)`中,可以定义多个方法来 ...

那可不可以这样理解 :

把所有按钮的click语句放在class MyThread(QThread):里

把click的Def函数放class MyThread(QThread)外,

期间每个按钮click调用def后,就operation_finished = Signal(str)一次。

下一个按钮click调用def后,又operation_finished = Signal(str)一次?

是这样吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 21:23:33 | 显示全部楼层
yxxxzx123 发表于 2024-03-14 21:23
那可不可以这样理解 :

把所有按钮的click语句放在 ...


抱歉,我之前的解释可能有些混乱。让我来重新梳理一下。

在`class MyThread(QThread)`中,我们可以把每个按钮的操作定义为一个独立的方法(`def`函数)。在该类之外,我们可以定义一个信号(`operation_finished = Signal(str)`),用于在每个按钮操作完成后发射信号。

然后,在点击按钮时,我们创建一个线程对象,并将对应按钮的操作方法传递给线程。在线程内部,执行操作方法,并在操作完成后发射信号通知主线程。下面是一个示例:
from PySide6.QtCore import QThread, Signal

# 创建自定义的线程类
class MyThread(QThread):
    operation_finished = Signal(str)

    def __init__(self, operation):
        super().__init__()
        self.operation = operation

    def run(self):
        # 在线程内部执行操作方法
        self.operation()
        # 操作完成后发射信号
        self.operation_finished.emit("操作完成")

# 创建线程对象并连接信号与槽函数
thread = MyThread(operation_A)
thread.operation_finished.connect(my_slot)

# 点击按钮后启动线程
button.clicked.connect(thread.start)

在上述示例中,我们创建了一个`MyThread`线程类,通过在初始化方法中传递对应按钮的操作方法,将其保存在`self.operation`属性中。在`run`方法中,执行`self.operation()`即可执行对应按钮的操作。

在主线程中,通过创建`thread`对象,并连接其`operation_finished`信号与槽函数。当点击按钮时,调用`thread.start()`方法启动线程。

请注意,这里的`operation_A`是指代某个按钮的操作方法,在使用时需要根据实际情况进行修改和补充。

希望这次的解释能够更清晰明了,如果还有疑问,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 21:28:24 | 显示全部楼层
FishC 发表于 2024-3-14 21:23
抱歉,我之前的解释可能有些混乱。让我来重新梳理一下。

在`class MyThread(QThread)`中,我们可以 ...


请原谅我很愚笨,我还是没懂。

我的理解是这样:

from PySide6.QtCore import QThread, Signal

# 创建自定义的线程类
class MyThread(QThread):
    operation_finished = Signal(str)

    def __init__(self, operation):
        super().__init__()
        self.operation = operation

    def run(self):
        # 在线程内部执行操作方法
        按钮1.click.connect.def01
        # 操作完成后发射信号
        self.operation_finished.emit("操作完成")

      # 在线程内部执行操作方法
        按钮2.click.connect.def02
        # 操作完成后发射信号
        self.operation_finished.emit("操作完成")

# 在线程内部执行操作方法
        按钮3.click.connect.def03
        # 操作完成后发射信号
        self.operation_finished.emit("操作完成")


# 创建线程对象并连接信号与槽函数
thread = MyThread(operation_A)
thread.operation_finished.connect(my_slot)

# 点击按钮后启动线程
button.clicked.connect(thread.start)

def01 ...

def02...

def03....

我的理解 对不?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 21:28:49 | 显示全部楼层
yxxxzx123 发表于 2024-03-14 21:28
请原谅我和愚笨,我还是没懂。

我的理解 是这样:
...


不用担心,让我来帮助您理解。您的逻辑接近正确,但是还有一些概念需要进行澄清。

首先,`QPushButton`的`clicked`信号并不是一个函数,因此不能使用`connect`语句将其连接到自定义的函数上。相反,我们应该为每个按钮创建一个点击事件处理函数,并在其中执行对应的操作。

其次,为了使多线程起作用,我们需要在`run`方法中启动每个操作。这意味着,在`run`方法中,我们只需要执行按钮点击事件处理函数,而不是将它们连接到信号上。

最后,为了确保在每个操作完成后发射信号,我们可以将信号的发射放在每个操作的末尾。

以下是一个修正后的示例代码:
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton
from PySide6.QtCore import QThread, Signal

# 创建自定义的线程类
class MyThread(QThread):
    operation_finished = Signal(str)
    
    def __init__(self):
        super().__init__()
        
    def run(self):
        # 在线程内部执行操作方法
        self.operation_A()
        # 操作完成后发射信号
        self.operation_finished.emit("操作A完成")
        
        # 在线程内部执行操作方法
        self.operation_B()
        # 操作完成后发射信号
        self.operation_finished.emit("操作B完成")
        
        # 在线程内部执行操作方法
        self.operation_C()
        # 操作完成后发射信号
        self.operation_finished.emit("操作C完成")
        
    def operation_A(self):
        # 这里编写操作A的代码
        pass
    
    def operation_B(self):
        # 这里编写操作B的代码
        pass
    
    def operation_C(self):
        # 这里编写操作C的代码
        pass

# 创建主窗口
app = QApplication([])
window = QMainWindow()

# 创建按钮
button = QPushButton("点击按钮")

# 创建线程对象 
thread = MyThread()
# 连接信号和槽函数
thread.operation_finished.connect(my_slot)

# 点击按钮后启动线程
button.clicked.connect(thread.start)

# 显示主窗口
window.setCentralWidget(button)
window.show()

# 运行应用程序
app.exec()

在上述示例中,我们定义了一个`MyThread`线程类,其中包含了三个操作方法(`operation_A`、`operation_B`和`operation_C`)。在这些方法中,我们可以编写具体的操作代码。

在`MyThread`的`run`方法中,我们按顺序执行了这些操作,并在每个操作完成后发射信号。

然后,我们创建了一个主窗口,并在其中添加了一个按钮。当按钮被点击时,它会启动线程并执行其中的操作。

最后,我们连接了线程的`operation_finished`信号与槽函数`my_slot`,以便在每个操作完成后进行处理。

希望这次的解释能够更加清晰,并帮助您理解多线程的使用。如果您还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-14 21:34:15 | 显示全部楼层
FishC 发表于 2024-3-14 21:28
不用担心,让我来帮助您理解。您的逻辑接近正确,但是还有一些概念需要进行澄清。

首先,`QPushButt ...

难道你的意思是一个class MyThread(QThread):只能对应1个按钮?

然后把这个按钮的每一步(共3步操作如A打开工作簿、B遍历工作簿所有sheet、C再读取每个sheet的每个单元格操作)分解成def operation_A(self)、def operation_A(self)和def operation_C(self)?
        
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-23 11:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表