如何在Delphi中以各种方式选择线程?

lke*_*ler 63 delphi multithreading asynchronous

看来我终于要在我的Delphi 2009程序中实现某种线程.如果只有一种方法可以做到这一点,我就会开始跑步.但我看到了几种可能性.

任何人都可以解释这些之间的差异以及为什么我选择一个而不是另一个.

  1. Delphi中的TThread类

  2. AsyncCalls安德烈亚斯Hausladen

  3. OmniThreadLibrary by Primoz Gabrijelcic(gabr)

  4. ......还有其他人吗?


编辑:

我刚读了Gabr在2010年3月(第10期)Blaise Pascal杂志上发表的一篇精彩文章,名为"创造线索的四种方法".你必须订阅获取杂志的内容,所以根据版权,我不能在这里重现任何实质性的内容.

总之,Gabr描述了使用TThreads,直接Windows API调用,Andy的AsyncCalls和他自己的OmniThreadLibrary之间的区别.他的结论是:

"我不是说你必须选择除了经典的德尔福方式(TThread)以外的任何东西,但是你知道你拥有的选择仍然很好"

Mghie的答案非常透彻,暗示OmniThreadLibrary可能更可取.但是我仍然对每个人关于我(或任何人)应该如何为他们的应用选择他们的线程方法的意见感兴趣.

您可以添加到列表中:

.4.直接调用Windows API

.5. 米莎Charrett的 CSI分布式应用程序框架,通过LachlanG在答复建议.


结论:

我可能会选择OmniThreadLibrary.我喜欢加布尔的作品.我多年前使用过他的探查器GPProfile,而我现在正在使用他的GPStringHash,它实际上是OTL的一部分.

一旦Embarcadero将该功能添加到Delphi中,我唯一关心的可能就是升级它以使用64位或Unix/Mac处理.

mgh*_*hie 43

如果您没有多线程经验,那么您可能不应该开始TThread,因为它只是本机线程上的薄层.我认为它的边缘也有点粗糙; 自从Delphi 2引入以来,它没有发展很多,主要是在Kylix时间框架内允许Linux兼容性的更改,以及纠正更明显的缺陷(比如修复损坏的MREW类,最后弃用Suspend()Resume()最新的Delphi版本) ).

使用简单的线程包装器类基本上也会导致开发人员专注于太低的级别.为了正确使用多个CPU内核,关注任务而不是线程更好,因为使用线程分配工作并不能很好地适应不断变化的需求和环境 - 取决于硬件和其他并行运行的软件的最佳数量即使在同一系统的不同时间,线程也可能有很大差异.一个只传递大量工作的库,并且自动安排它们以充分利用可用资源的库在这方面有很大帮助.

AsyncCalls是将线程引入应用程序的第一步.如果程序中有几个区域需要执行多个彼此独立的耗时步骤,那么您可以通过将每个区域传递给AsyncCalls来异步执行它们.即使您只有一个这样耗时的操作,您也可以异步执行它,只需在VCL线程中显示进度UI,可选择允许取消操作.

AsyncCalls对于在整个程序运行期间保持不变的后台工作者而言不太适合IMO,并且当程序中的某些对象具有线程关联性时可能无法使用(如数据库连接或OLE对象可能需要全部调用发生在同一个线程中).

您还需要注意的是,这些异步操作属于"即发即忘"类型.每个重载AsyncCall()函数都会返回一个IAsyncCall接口指针,如果要避免阻塞,可能需要保留引用.如果你没有保留引用,那么当ref计数达到零时,接口将被释放,这将导致线程释放接口以等待异步调用完成.这是您在调试时可能会看到的内容,退出创建该方法的方法IAsyncCall可能需要花费大量时间.

在我看来,OTL是你的三个选项中最通用的,我会毫不犹豫地使用它.它可以做任何事情TThread,AsyncCalls可以做,还有更多.它具有完善的高级设计,既可以让用户轻松生活,也可以让端口连接到Unixy系统(同时保持大部分接口完好无损),即使不容易也是如此.在过去的几个月里,它也开始为并行工作获得一些高级构造,强​​烈推荐.

OTL也有几十个样本,这对于入门非常重要.AsyncCalls在评论中只有几行,但由于其功能有限,它很容易理解(它只做一件事,但它做得很好).TThread只有一个样本,这个样本在14年内没有真正改变,并且主要是如何不做事情的一个例子.

无论您选择哪种选项,任何库都不会消除理解线程基础知识的需要.读完一本关于这些的好书是任何成功编码的先决条件.例如,适当的锁定是所有这些的必要条件.

  • 出色的回应.我刚刚开始探索为我的应用程序添加线程,这些线程偶尔会与我的数据库进行冗长的对话,而我真的希望它像一位失去线程的公众演讲者一样停在那里.我只需要这种概述. (3认同)

Lac*_*anG 7

还有另一个鲜为人知的Delphi线程库,Misha Charrett的CSI应用框架.

它基于消息传递而不是共享内存.相同的消息传递机制用于在同一进程或其他进程中运行的线程之间进行通信,因此它既是线程库又是分布式进程间通信库.

开始时有一些学习曲线但是一旦你开始,你不必担心所有传统的线程问题,比如死锁和同步,框架会为你处理大部分问题.

Misha多年来一直在开发这个产品,并且一直在积极改进框架和文档.他总是对支持问题非常敏感.


Mas*_*ler 6

TThread是一个封装Windows线程的简单类.使用Execute方法创建一个后代类,该方法包含此线程应执行的代码,创建线程并将其设置为运行并执行代码.

AsyncCalls和OmniThreadLibrary都是在线程之上构建更高级别概念的库.它们是关于任务,需要异步执行的离散工作.你启动库,它设置一个任务池,一组特殊线程,其工作是等待你为它们工作,然后你传递一个包含代码的函数指针(或方法指针或匿名方法)需要执行,并在一个任务池线程中执行它,并为您处理许多低级细节.

我没有使用任何一个库,所以我不能真正给你两者之间的比较.尝试一下,看看他们能做些什么,哪一个对你感觉更好.


小智 6

(对不起,我没有足够的评论点,所以我把它作为答案,而不是另一个投票给OTL)

我使用过TThread,CSI和OmniThread(OTL).这两个库都有非平凡的学习曲线,但比TThread更强大.我的结论是,如果你要做任何有关线程的重要事情,你最终还是会编写一半的库函数,所以你不妨从别人写的工作调试版本开始.Misha和Gabr都是比我们大多数人更好的程序员,所以他们做得比我们做得更好.

我看过AsyncCalls,但它没有做我想要的.它确实有一个"同步"功能(从OTL中丢失),所以如果你依赖于它,你可能会完全依赖于AynscCalls.使用消息传递的IMO并不足以证明Synchronize的肮脏,因此请关闭并学习如何使用消息.

在我喜欢OTL的三个中,主要是因为收集了例子,但也因为它更加独立.如果您已经使用JCL或者您只在一个地方工作,这不是一个问题,但我做的包括合同工作和销售客户安装Misha的系统比OTL更难,只是因为OTL是~20个文件在一个目录中.这听起来很傻,但对很多人来说很重要.

使用OTL,搜索关键字的示例和源代码,并在论坛中提问,这对我来说很有用.我熟悉传统的"卸载CPU密集型任务"线程作业,但是现在我正在研究一堆数据库工作的背景,这些工作有更多的"线程阻塞等待DB"而不是"CPU最大化", OTL对此非常有效.主要区别在于我可以运行30多个线程,而不会占用CPU最大值,但通常不可能停止运行.