转帖:DELPHI用const来提高应用程序在多核多线程下的性能

本文探讨了在Delphi中使用const关键字来提高多线程或多核环境下应用程序的执行效率。通过减少字符串和结构体类型的复制操作,const能够有效避免因内存管理锁竞争导致的线程等待,从而提升程序性能。

原帖地址:http://hi.baidu.com/sqldebug/blog/item/07f436104f53ea5af819b8be.html

我们经常在DELPHI中用const来定义常量,用const来保护函数参数,其实在用const保护函数参数还有另一个更为重要的作用,提高应用程序的执行效率,尤其是在多线程多核下效果更明显。原因是:普通的函数参数如Add(AValue: string),编译器在传入参数的时候先把变量复制一份,然后当成AValue传入Add,函数结束的时候进行销毁,你在参数上加了const,编译器在传入参数的时候不会进行复制,而是直接传地址,并在编译期间检查不能修改AValue值,我们知道DELPHI的内存管理在申请内存的时候是会加锁的,因此如果调用函数频繁,而且没有加const,这样会造成线程排队等候,性能会不如单线程,const只是对string、结构体等非基本类型有提高效率的作用,对Integer等基本类型(栈变量)不起作用。

1、const的类型检查,以下代码可以修改const参数的值

Delphi(Pascal) code
   
procedure TFmMain.EditConstParameter( const ARecordTest: TRecordTest); var pPoint: PRecordTest; begin pPoint : = @ARecordTest; pPoint.A : = 1 ; ShowMessage(IntToStr(ARecordTest.A)); end ; procedure TFmMain.btnEditConstClick(Sender: TObject); var ARecordTest: TRecordTest; begin ARecordTest.A : = 0 ; EditConstParameter(ARecordTest); Inc(ARecordTest.A); ShowMessage(IntToStr(ARecordTest.A)); end ;



2、const提高代码性能,使用const提高代码性能,大家可以把以下例子在自己电脑上测试。

Delphi(Pascal) code
   
unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, DateUtils; const WM_Complete = WM_USER + 1001 ; type TRecordTest = record A: Integer; B: Integer; C: Integer; D: Integer; E: Integer; F: Integer; AStr: string; BStr: string; CStr: string; DStr: string; EStr: string; FStr: string; FCommit: array [ 0 .. 15 * 1024 * 4 ] of Char; end ; PRecordTest = ^TRecordTest; TTestThread = class; TFmMain = class(TForm) grpConst: TGroupBox; cbbConstThreadNum: TComboBox; lblThreadConst: TLabel; btnConstStart: TButton; btnConstStop: TButton; grp1: TGroupBox; lbl1: TLabel; cbbUnConstThreadNum: TComboBox; btnUnConstStart: TButton; btnUnConstStop: TButton; mmoText: TMemo; btnEditConst: TButton; procedure btnConstStartClick(Sender: TObject); procedure btnConstStopClick(Sender: TObject); procedure btnUnConstStartClick(Sender: TObject); procedure btnUnConstStopClick(Sender: TObject); procedure btnEditConstClick(Sender: TObject); private { Private declarations } FStartTime, FEndTime: TDateTime; FConstThread, FUnConstThread: array of TTestThread; protected procedure WMComplete( var Msg: TMessage); message WM_Complete; public { * 修改const函数变量 * } procedure EditConstParameter( const ARecordTest: TRecordTest); { * 线程测试函数 * } function ConstTestA( const ARecordTest: TRecordTest): Integer; function ConstTestB( const ARecordTest: TRecordTest): Integer; function ConstTestC( const ARecordTest: TRecordTest): Integer; function ConstTestD( const ARecordTest: TRecordTest): Integer; function ConstTestE( const ARecordTest: TRecordTest): Integer; function ConstTestF( const ARecordTest: TRecordTest): Integer; function UnConstTestA(ARecordTest: TRecordTest): Integer; function UnConstTestB(ARecordTest: TRecordTest): Integer; function UnConstTestC(ARecordTest: TRecordTest): Integer; function UnConstTestD(ARecordTest: TRecordTest): Integer; function UnConstTestE(ARecordTest: TRecordTest): Integer; function UnConstTestF(ARecordTest: TRecordTest): Integer; end ; TTestThread = class(TThread) private FConst: Boolean; protected procedure Execute; override; end ; var FmMain: TFmMain; implementation { $R *.dfm } { TFmMain } procedure TFmMain.EditConstParameter( const ARecordTest: TRecordTest); var pPoint: PRecordTest; begin pPoint : = @ARecordTest; pPoint.A : = 1 ; ShowMessage(IntToStr(ARecordTest.A)); end ; procedure TFmMain.btnEditConstClick(Sender: TObject); var ARecordTest: TRecordTest; begin ARecordTest.A : = 0 ; EditConstParameter(ARecordTest); Inc(ARecordTest.A); ShowMessage(IntToStr(ARecordTest.A)); end ; function TFmMain.ConstTestA( const ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; ConstTestB(ARecordTest); end ; function TFmMain.ConstTestB( const ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; ConstTestC(ARecordTest); end ; function TFmMain.ConstTestC( const ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; ConstTestD(ARecordTest); end ; function TFmMain.ConstTestD( const ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; ConstTestE(ARecordTest); end ; function TFmMain.ConstTestE( const ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; ConstTestF(ARecordTest); end ; function TFmMain.ConstTestF( const ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; end ; function TFmMain.UnConstTestA(ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; UnConstTestB(ARecordTest); end ; function TFmMain.UnConstTestB(ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; UnConstTestC(ARecordTest); end ; function TFmMain.UnConstTestC(ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; UnConstTestD(ARecordTest); end ; function TFmMain.UnConstTestD(ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; UnConstTestE(ARecordTest); end ; function TFmMain.UnConstTestE(ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; UnConstTestF(ARecordTest); end ; function TFmMain.UnConstTestF(ARecordTest: TRecordTest): Integer; var i, j: Integer; begin j : = ARecordTest.A; for i : = 0 to 5 do begin j : = j + 1 ; end ; Result : = j; end ; procedure TFmMain.WMComplete( var Msg: TMessage); begin FEndTime : = Now; mmoText.Lines.Add( ' Spend Time: ' + IntToStr(MilliSecondsBetween(FStartTime, FEndTime))); end ; { TTestThread } procedure TTestThread.Execute; var ARecordTest: TRecordTest; begin inherited; ARecordTest.A : = 0 ; while ARecordTest.A < 1000000 do begin if FConst then begin Inc(ARecordTest.A); FmMain.ConstTestA(ARecordTest); end else begin Inc(ARecordTest.A); FmMain.UnConstTestA(ARecordTest); end ; end ; SendMessage(FmMain.Handle, WM_Complete, 0 , 0 ); end ; procedure TFmMain.btnConstStartClick(Sender: TObject); var i: Integer; begin FStartTime : = Now; SetLength(FConstThread, StrToInt(cbbConstThreadNum.Text)); for i : = Low(FConstThread) to High(FConstThread) do begin FConstThread[i] : = TTestThread.Create(True); FConstThread[i].FreeOnTerminate : = True; FConstThread[i].FConst : = True; end ; for i : = Low(FConstThread) to High(FConstThread) do begin FConstThread[i].Resume; end ; btnConstStart.Enabled : = False; btnConstStop.Enabled : = True; end ; procedure TFmMain.btnConstStopClick(Sender: TObject); var i: Integer; begin if Length(FConstThread) = 0 then Exit; for i : = Low(FConstThread) to High(FConstThread) do begin FConstThread[i].Terminate; end ; SetLength(FConstThread, 0 ); btnConstStart.Enabled : = True; btnConstStop.Enabled : = False; end ; procedure TFmMain.btnUnConstStartClick(Sender: TObject); var i: Integer; begin FStartTime : = Now; SetLength(FUnConstThread, StrToInt(cbbUnConstThreadNum.Text)); for i : = Low(FUnConstThread) to High(FUnConstThread) do begin FUnConstThread[i] : = TTestThread.Create(True); FUnConstThread[i].FreeOnTerminate : = True; FUnConstThread[i].FConst : = False; end ; for i : = Low(FUnConstThread) to High(FUnConstThread) do begin FUnConstThread[i].Resume; end ; btnUnConstStart.Enabled : = False; btnUnConstStop.Enabled : = True; end ; procedure TFmMain.btnUnConstStopClick(Sender: TObject); var i: Integer; begin if Length(FUnConstThread) = 0 then Exit; for i : = Low(FUnConstThread) to High(FUnConstThread) do begin FUnConstThread[i].Terminate; end ; SetLength(FUnConstThread, 0 ); btnUnConstStart.Enabled : = True; btnUnConstStop.Enabled : = False; end ; end .
 
### 多线程在 Qt GUI 应用程序中的应用 Qt GUI 应用程序的主线程负责处理界面更新和事件循环。如果在主线程中执行耗时操作,例如网络请求、文件读写或图像解码,会导致界面冻结,降低用户体验。为了解决这一问题,可以通过多线程机制将耗时任务从主线程移出,从而提升应用程序的响应速度和整体性能 [^3]。 #### 使用 QThread 实现线程管理 `QThread` 是 Qt 提供的基础线程类,允许开发者创建独立运行的任务。通过继承 `QThread` 并重写 `run()` 方法,可以定义在子线程中执行的操作。这种方式适用于需要长时间运行且不依赖主线程资源的任务。 ```cpp class WorkerThread : public QThread { Q_OBJECT protected: void run() override { // 执行耗时操作 QImage image = decodeFrame(); emit resultReady(image); } signals: void resultReady(const QImage &image); }; ``` 启动线程后,主线程将继续响应用户交互,而耗时计算将在后台进行 [^2]。 #### 基于 QObject 的线程模型 另一种更灵活的方式是使用 `moveToThread()` 将对象移动到指定线程中执行。这种方法避免了直接继承 `QThread`,更适合面向对象的设计模式。 ```cpp class Worker : public QObject { Q_OBJECT public slots: void process() { // 执行复杂任务 QImage image = heavyComputation(); emit finished(image); } signals: void finished(const QImage &image); }; // 创建线程并绑定工作对象 Worker *worker = new Worker(); QThread *thread = new QThread(this); worker->moveToThread(thread); connect(thread, &QThread::started, worker, &Worker::process); connect(worker, &Worker::finished, thread, &QThread::quit); connect(worker, &Worker::finished, this, &MainWindow::updateUI); thread->start(); ``` 这种设计使线程管理和任务调度更加清晰,并且便于集成进现有的信号槽机制中 [^4]。 #### 利用 QtConcurrent 简化异步编程 对于简单的并发需求,`QtConcurrent` 提供了一组高级 API,支持并行执行函数调用而不必手动管理线程生命周期。 ```cpp QFuture<QImage> future = QtConcurrent::run(decodeFrame, frameData); QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this); watcher->setFuture(future); connect(watcher, &QFutureWatcher<QImage>::finished, [=]() { QImage result = watcher->future().result(); updateUI(result); }); ``` 该方法特别适合一次性任务或不需要长期运行的工作流 [^1]。 #### 保证线程安全与同步 由于 Qt 的 GUI 组件必须在主线程中访问,所有从子线程获取的数据都需要通过信号槽传递回主线程。此外,在多个线程同时访问共享资源时,应使用互斥锁(如 `QMutex`)或原子操作来防止数据竞争。 ```cpp QMutex mutex; void sharedDataAccess() { QMutexLocker locker(&mutex); // 安全地访问共享数据 } ``` 合理利用这些同步工具可确保程序稳定性 [^2]。 ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值