95-多线程、线程池、定时器-线程池

QThreadPool是Qt用于管理线程的工具,它自动回收QThread对象以降低创建成本。每个Qt应用有一个全局实例,可通过QRunnable子类化实现任务。线程池自动删除QRunnable,默认30秒无活动线程会过期。它支持最大线程数设置,以及线程保留和释放功能,适用于并发执行任务的场景。
摘要由CSDN通过智能技术生成

线程池

QThreadPool

img

QThreadPool管理和回收单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。

每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问该对象。

from PySide6.QtCore import QThreadPool

QThreadPool(parent: Union[PySide6.QtCore.QObject,NoneType] = None)-> None
QThreadPool官方描述

要使用QThreadPool线程之一,请子类QRunable并实现run()虚拟函数。然后创建该类的对象并将其传递给start()。

class HelloWorldTask(QRunnable):

    def run():

        print("Hello world from thread",QThread.currentThread())


hello = HelloWorldTask()
# QThreadPool takes ownership and deletes 'hello'automatically
QThreadPool.globalInstance().start(hello)
  • 默认情况下,QThreadPool 会自动删除 QRunnable。使用 setAutoDelete()更改自动删除标志。

  • QThreadPool 支持通过从 run()中调用 tryStart(this)多次执行相同的 QRunnable。

    • 如果启用了自动删除,则当最后一个线程退出运行函数时,将删除 QRunnable。
    • 启用自动删除时,使用相同的 QRunnable 多次调用 start()会产生争用条件,不建议这样做。
  • 在一定时间内未使用的线程将过期。默认到期超时为 30000 毫秒(30 秒)。这可以使用 setExpiryTimeout()进行更改。设置负到期超时将禁用到期机制。

  • 调用 maxThreadCount()查询要使用的最大线程数。如果需要,您可以使用 setMaxThreadCount()更改限制。默认的 maxThreadCount()是 idealThreadCount()。activeThreadCount()函数返回当前正在工作的线程数。

  • reserveThread()函数保留一个线程供外部使用。当你完成线程时,请使用 releaseThread(),以便可以重用它。从本质上讲,这些功能会暂时增加或减少活动线程计数,并且在实现 QThreadPool 不可见的耗时操作时很有用。

QThreadPool方法

请注意,QThreadPool 是用于管理线程的低级类,有关更高级别的替代方案,请参阅 Qt 并发模块。

方法说明
activeThreadCount()此属性保存线程池中活动线程的数量。。
clear()从队列中删除尚未启动的可运行文件。runnable->autoDelete()返回true的可运行文件将被删除。
contains(thread)如果线程是由该线程池管理的线程,则返回true。
expiryTimeout()此属性以毫秒为单位保存线程过期超时值。。
在expiryTimeout毫秒内未使用的线程被视为已过期并将退出。这些线程将根据需要重新启动。默认expiryTimeout为30000毫秒(30秒)。如果expiryTimeout为负,则新创建的线程不会过期,例如,在线程池被销毁之前,它们不会退出。
注意,设置expiryTimeout对已经运行的线程没有影响。只有新创建的线程才会使用新的expiryTimeout。我们建议在创建线程池之后,但在调用start()之前立即设置expiryTimeout
maxThreadCount()此属性保存线程池使用的最大线程数。在创建QThreadPool对象时,此属性将默认为idealThreadCount()的值。
releaseThread()释放先前通过调用reservedThread()保留的线程。
reserveThread()保留一个线程,忽略activeThreadCount()和maxThreadCount(()。完成线程后,调用releaseThread()以允许重用它。
即使保留maxThreadCount()线程或更多线程,线程池仍将允许至少一个线程。
此函数将增加报告的活动线程数。这意味着通过使用此函数,activeThreadCount()可以返回一个大于maxThreadCount(()的值。
setExpiryTimeout(expiryTimeout)此属性以毫秒为单位保存线程过期超时值。。
在expiryTimeout毫秒内未使用的线程被视为已过期并将退出。这些线程将根据需要重新启动。默认expiryTimeout为30000毫秒(30秒)。如果expiryTimeout为负,则新创建的线程不会过期,例如,在线程池被销毁之前,它们不会退出。
注意,设置expiryTimeout对已经运行的线程没有影响。只有新创建的线程才会使用新的expiryTimeout。我们建议在创建线程池之后,但在调用start()之前立即设置expiryTimeout
setMaxThreadCount(maxThreadCount)此属性保存线程池使用的最大线程数。在创建QThreadPool对象时,此属性将默认为idealThreadCount()的值。
线程池将始终至少使用1个线程,即使maxThreadCount限制为零或负。
setStackSize(stackSize)此属性保存线程池工作线程的堆栈大小。。
该属性的值仅在线程池创建新线程时使用。更改它对已创建或正在运行的线程无效。
默认值为0,这使QThread使用操作系统默认堆栈大小。
setThreadPriority(priority)此属性保存新工作线程的线程优先级。。
该属性的值仅在线程池启动新线程时使用。更改它对已经运行的线程没有影响。
默认值为InheritPriority,这使QThread使用与QThreadPool对象所在的优先级相同的优先级。
stackSize()此属性保存线程池工作线程的堆栈大小。。
该属性的值仅在线程池创建新线程时使用。更改它对已创建或正在运行的线程无效。
默认值为0,这使QThread使用操作系统默认堆栈大小。
start(arg__1[,priority=0])arg__1 – PyCallable
priority – int
start(runnable[,priority=0])runnable – PySide6.QtCore.QRunnable
priority – int
保留一个线程并使用它来运行可运行的线程,除非该线程将使当前线程计数超过maxThreadCount()。在这种情况下,runable将被添加到运行队列中。优先级参数可用于控制运行队列的执行顺序。
注意,如果runnable->autoDelete()返回true,线程池将拥有可运行文件的所有权,并且在runnable->run()返回后,线程池会自动删除可运行文件。如果runnable->autoDelete()返回false,则runnable的所有权仍属于调用者。请注意,在调用此函数后更改runable上的自动删除会导致未定义的行为。
startOnReservedThread(runnable)runnable – PySide6.QtCore.QRunnable
释放先前使用reserveThread()保留的线程,并使用它运行可运行的线程。
注意,如果runnable->autoDelete()返回true,线程池将拥有可运行文件的所有权,并且在runnable->run()返回后,线程池会自动删除可运行文件。如果runnable->autoDelete()返回false,则runnable的所有权仍属于调用者。请注意,在调用此函数后更改runable上的自动删除会导致未定义的行为。
threadPriority()此属性保存新工作线程的线程优先级。。
该属性的值仅在线程池启动新线程时使用。更改它对已经运行的线程没有影响。
默认值为InheritPriority,这使QThread使用与QThreadPool对象所在的优先级相同的优先级。
tryStart(arg__1)RETURN TYPE bool
tryStart(runnable)arg__1 – PyCallable
RETURN TYPE bool
tryTake(runnable)PARAMETERS runnable – PySide6.QtCore.QRunnable
RETURN TYPE bool
如果指定的可运行文件尚未启动,则尝试将其从队列中删除。如果runnable尚未启动,则返回true,runnable的所有权将转移给调用者(即使runnable->autoDelete()=true)。否则返回false。
如果runnable->autoDelete()=true,则此函数可能会删除错误的runnable。这被称为ABA问题:原始的可运行文件可能已经执行,并且已经被删除。内存被重新用于另一个可运行文件,然后将其移除,而不是预期的。因此,我们建议仅对非自动删除的可运行文件调用此函数。
waitForDone([msecs=-1])msecs – int
RETURN TYPE bool
等待所有线程退出并从线程池中删除所有线程,最长为毫秒。如果删除了所有线程,则返回true;否则返回false。如果毫秒为-1(默认值),则忽略超时(等待最后一个线程退出)。
[Static]globalInstance()RETURN TYPE PySide6.QtCore.QThreadPool
返回全局QThreadPool实例。

QRunnable

QRunnable 类是所有可运行对象的基类。

QRunnable类是一个接口,用于表示需要执行的任务或代码片段,由run()函数的重新实现表示。

您可以使用QThreadPool在单独的线程中执行您的代码。如果autoDelete()返回true(默认值),QThreadPool会自动删除QRunnable。使用setAutoDelete()更改自动删除标志。

QThreadPool支持通过在run()函数中调用try Start(this)多次执行相同的QRunnable。如果启用了autoDelete,则QRunnable将在最后一个线程退出run函数时被删除。启用autoDelete时使用相同的QRunnable多次调用start()会创建竞争条件,不推荐使用。

from PySide6.QtCore import QRunnable

QRunnable(self)-> None 
方法说明
autoDelete()–>bool返回true是启用自动删除;否则为假。

如果启用了自动删除,QThreadPool将在调用run()后自动删除此runnable;否则,所有权仍属于应用程序程序员。
setAutoDelete(autoDelete:bool)如果autoDelete为真,则启用自动删除;否则禁用自动删除。

如果启用了自动删除,QThreadPool将在调用run()后自动删除此runnable;否则,所有权仍属于应用程序程序员。

请注意,必须在调用start()之前设置此标志。在start()之后调用此函数会导致未定义的行为。
run()在子类中实现这个纯虚拟函数。
在 WPF 中,使用多线程定时器可以帮助我们更好地管理界面的响应和处理复杂的任务。下面介绍一些常用的线程和定时器相关的类和方法。 线程相关的类和方法: 1. Thread 类:表示一个独立的线程,可以使用 Start 方法启动线程,使用 Join 方法等待线程结束。 2. ThreadPool 类:表示一个线程池,可以使用 QueueUserWorkItem 方法将任务添加到线程池中执行。 3. Dispatcher 类:表示一个 WPF 程序的消息循环,可以使用 Invoke 或 BeginInvoke 方法在 UI 线程上执行代码。 定时器相关的类和方法: 1. Timer 类:表示一个定时器,可以使用 Start 方法启动定时器使用 Stop 方法停止定时器。 2. DispatcherTimer 类:表示一个 WPF 程序的定时器,可以使用 Start 方法启动定时器使用 Stop 方法停止定时器。 下面是一个使用多线程定时器的示例代码: ```csharp public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // 创建一个新线程,并将任务添加到线程池中执行 ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork)); // 创建一个定时器,并设置间隔时间为1秒 DispatcherTimer timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(1); timer.Tick += Timer_Tick; timer.Start(); } // 定时器的 Tick 事件处理方法 private void Timer_Tick(object sender, EventArgs e) { // 在 UI 线程上更新界面 Dispatcher.Invoke(() => { lblTime.Content = DateTime.Now.ToString(); }); } // 新线程执行的任务 private void DoWork(object state) { // 在新线程上执行耗时操作 Thread.Sleep(5000); // 在 UI 线程上更新界面 Dispatcher.Invoke(() => { lblResult.Content = "任务完成!"; }); } } ``` 在上面的代码中,我们使用了一个新线程来执行一个耗时的任务,并使用定时器在 UI 线程上更新界面。通过多线程定时器的结合使用,我们可以更好地管理界面的响应和处理复杂的任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

士别三日,当挖目相待

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值