如何在Delphi中以各种方式进行线程处理?
似乎我终于在我的Delphi 2009程序中实现了某种线程化。 如果只有一种方法可以做到,我就可以跑步了。 但是我看到了几种可能性。
任何人都可以解释这些之间有什么区别,为什么我会select另一个。
-
Delphi中的TThread类
-
由Andreas Hausladen提供的 AsyncCalls
-
OmniThreadLibrary由Primoz Gabrijelcic(gabr)
-
…任何其他人?
编辑:
我刚刚在2010年3月(第10期)“ 布莱斯·帕斯卡杂志 ”( Blaise Pascal Magazine)的一篇题为“四种创造线索”的文章中,阅读了Gabr的一篇优秀文章。 你必须订阅获得杂志的内容,所以通过版权,我不能在这里再现任何实质性内容。
总之,Gabr描述了使用TThreads,直接Windows API调用,Andy的AsyncCalls和他自己的OmniThreadLibrary之间的区别。 他最后得出结论:
“我并不是说你不得不select比传统的delphi方式(TThread)还要多的东西,但是把你的select通知你还是很好的”
Mghie的回答非常彻底,build议OmniThreadLibrary可能更可取。 但是我仍然对每个人(或者任何人)应该如何select他们的线程方法感兴趣。
你可以添加到列表中:
。 4.直接调用Windows API
。 5. LachlanG在答复中提出的Misha Charrett的 CSI分布式应用程序框架 。
结论:
我可能会去OmniThreadLibrary。 我喜欢Gabr的工作。 多年前我使用过他的profiler GPProfile,而且我正在使用他的GPStringHash,它实际上是OTL的一部分。
一旦Embarcadero将这个function添加到Delphi中,我唯一的担心就是升级它来处理64位或者Unix / Mac处理。
如果你对multithreading没有经验,那么你可能不应该从TThread
开始,因为它只是一个本地线程的薄层。 我认为这也是有点粗糙的边缘; 自从Delphi 2引入以来,并没有发生很大的变化,主要是为了在Kylix时间框架中允许Linux的兼容性,以及纠正更明显的缺陷(如修复已损坏的MREW类,并最终废弃Suspend()
和Resume()
在最新的delphi版本)。
使用简单的线程包装类基本上也会导致开发人员将注意力集中在太低的级别上。 为了正确使用多个CPU内核,专注于任务而不是线程是更好的,因为用线程工作的划分不能适应不断变化的需求和环境 – 取决于硬件和其他并行运行的软件,最佳数目线程可能差别很大,即使在同一个系统的不同时间。 一个只传递大量工作的库,并且自动调度它们以充分利用可用资源,这在很大程度上是有帮助的。
AsyncCalls是将线程引入到应用程序中的第一步。 如果您的程序中有几个区域需要执行相互独立的大量耗时的步骤,则可以通过将每个步骤传递给AsyncCalls来asynchronous执行它们。 即使你只有一个这样耗时的操作,你可以asynchronous执行它,并简单地在VCL线程中显示一个进度UI,可选地允许取消操作。
AsyncCalls对于那些在整个程序运行时期间停留的后台工作人员来说是不太好的,当程序中的某些对象具有线程关联性时(比如数据库连接或者OLE对象可能需要所有的对象调用发生在同一个线程中)。
你还需要注意的是,这些asynchronous操作不是 “即发即忘”的。 每个重载的AsyncCall()
函数都会返回一个IAsyncCall
接口指针,如果您想避免阻塞,您可能需要保留一个引用。 如果不保留引用,那么当ref计数达到零时,接口将被释放,这将导致线程释放接口等待asynchronous调用完成。 这是您在debugging时可能会看到的情况,退出创buildIAsyncCall
的方法可能需要很长时间。
OTL在我看来是三种select中最通用的,我会毫不犹豫地使用它。 它可以做TThread
和AsyncCalls可以做的所有事情,还有更多。 它有一个完善的devise,既能让用户的生活更轻松,又能让一个Unixy系统的端口(尽pipe保持大部分接口完好无损)看起来至less有可能(如果不容易的话)。 在过去的几个月里,它也开始获得一些高水平的并行工作,强烈推荐。
OTL也有几十个样本,这对于开始很重要。 AsyncCalls在注释中只有几行,但是由于它的function有限,它很容易理解(它只做了一件事,但它做得很好)。 TThread
只有一个样本,这个样本在14年内并没有真正改变,大多数情况下是不做事的一个例子。
无论您select哪个选项,没有任何一个库会消除对线程基本知识的理解。 阅读好这本书是任何成功编码的先决条件。 例如正确的locking是所有这些要求。
TThread是封装Windows线程的简单类。 你用一个Execute方法创build一个后代类,该方法包含了这个线程应该执行的代码,创build线程并将其设置为运行并执行代码。
AsyncCalls和OmniThreadLibrary都是在线程之上构build更高级概念的库。 他们是关于任务 ,你需要asynchronous执行的离散工作。 你启动库,它build立一个任务池,一组特殊的线程,其工作是等待,直到你为他们工作,然后你传递一个函数指针(或方法指针或匿名方法)包含代码需要执行,并在任务池线程之一执行它,并为您处理大量的低级细节。
我没有使用过任何一个图书馆,所以我不能给你们两个之间的比较。 尝试一下,看看他们能做什么,哪一个对你感觉更好。
还有另一个不太为人所知的Delphi线程库,Misha Charrett的CSI应用程序框架 。
它基于消息传递而不是共享内存。 相同的消息传递机制用于在相同进程或其他进程中运行的线程之间进行通信,因此它既是线程库又是分布式进程间通信库。
开始有一些学习曲线,但一旦开始,您不必担心所有传统的线程问题,例如死锁和同步,框架会为您处理大部分问题。
Misha多年来一直在发展,并且一直在积极地改进框架和文档。 他总是对支持问题做出回应。
(对不起,我没有足够的评论意见,所以我把这个作为答案而不是OTL的另一个投票)
我用TThread,CSI和OmniThread(OTL)。 这两个库都有不平凡的学习曲线,但比TThread更有能力。 我的结论是,如果你要用线程去做任何重要的事情,那么最终你还是得编写一半的库函数,所以你最好还是从别人编写的工作,debugging版本开始。 Misha和Gabr都是比我们大多数人更好的程序员,所以他们比我们做得更好。
我已经看过AsyncCalls,但它没有做足够的我想要的。 有一件事是它有一个“同步”function(从OTL中没有),所以如果你依赖于这个function,你可能会单纯地使用AynscCalls。 国际海事组织使用消息传递并不足以certificate同步的缺陷,所以扣下来,学习如何使用消息。
在这三个我更喜欢OTL,主要是因为收集的例子,但也因为它是更独立。 如果你已经在使用JCL或者只在一个地方工作,那么这个问题就不那么严重了,但是在安装Misha的系统的时候,我做了一些包括合同工作和销售客户的组合,比OTL更难,仅仅是因为OTL是20个文件在一个目录中。 这听起来很愚蠢,但对很多人来说这很重要。
用OTLsearch关键词的例子和源代码的组合,并在论坛中提出问题为我工作。 我熟悉传统的“卸载CPU密集型任务”线程化作业,但是现在我正在研究一大堆数据库工作,它们有更多的“线程阻塞等待数据库”和更less的“CPU超时” OTL工作得很好。 主要的区别是我可以有30多个线程运行没有CPU超出,但停止一个通常是不可能的。
我知道这不是最先进的方法:-)也许它也有限制,但我只是尝试系统。 BeginThread ,发现它很简单 – 可能是因为我指的文档的质量… http://www.delphibasics.co.uk/RTL.asp?Name=BeginThread (国际海事组织尼尔莫法特可以教MSDN的东西或两个)
这是我在尝试学习新事物时发现的最大因素,文档的质量 ,而不是数量 。 只花了几个小时,然后我又回到了真正的工作,而不是担心如何让线程去做生意。
编辑实际上罗布·肯尼迪在这里解释BeginThread的BeginThread结构 – delphi很好的工作
编辑实际上罗布·肯尼迪在同一篇文章中解释TThread的方式,我想我会改变我的代码使用TThread明天。 谁知道下周会是什么样子! (AsyncCalls也许)