1

我正在研究一个看起来像某种时间问题的错误,所以我有点好奇事件在 Delphi 7 中是如何工作的。发生的情况是我们通过 COM 接口将一些数据发送到我们的应用程序并在从 COM 线程引发的事件。似乎事件中包含相当多的代码,执行时间越来越长,一段时间后整个应用程序崩溃。在事件中调用图形并填充到可能会影响时间的大型数组中。我无法发现内存使用量有任何显着增加,也没有机会运行任何分析器来检查泄漏。此外,要测试的显而易见的事情是剥离其中所有代码的事件,看看我们是否可以运行更长的时间。

Delphi中的事件是串行的还是并行的,也就是说,如果我在一个正在执行的时候得到一个新的事件——会发生什么?它是在某种自动线程上并行运行,是被忽略还是排队?

如果它被排队,在应用程序崩溃之前我可以在队列中有多少?

索引到一个大数组需要更长的时间吗?即使它是固定大小的?我认为不应该,所以我正在寻找需要时间的泄漏和分配。如果我通过事件收到一个对象,我应该在事件中还是在“调用”代码中处理它?

在 Delphi 中,哪些东西通常不能很好地扩展?我可以寻找什么会增加执行时间?

最后,由于这是与 COM 相关的,因此任何指向 COM 中常见陷阱的指针都值得赞赏,尽管我意识到这很棘手。不过,我确实掌握了共同初始化。

4

3 回答 3

2

Delphi 主要是串行处理事件。不幸的是,当您已经在某个事件中运行时,可以告诉 Delphi 处理其他事件。因此,当您的当前事件正在等待新事件完成时,新事件将运行。在最坏的情况下,您的应用程序可能看起来表现正常,而它实际上是在事件中的事件中堆叠事件。规则一:除非你真的需要,否则避免使用 Application.ProcessMessages。

使用 COM 对象时,事情会变得有点复杂,因为 COM 对象可能有它自己的事件、启动它自己的线程并执行所有其他类型的事情,而这些事情你没有任何控制权。COM 在 Delphi 中似乎很容易使用,但对于没有经验的开发人员来说,它确实有许多隐藏的陷阱。(在其中几个幸存后,我仍然有伤痕!)

一般来说,在处理 COM 对象时,我会尝试将 COM 调用分离到它们自己的线程中,创建特殊组件以将 COM 对象保持在它自己的线程中,并添加大量同步代码,这样我就可以保持 GUI 响应而一些长 COM 任务正在做一些处理。但是这样做需要大量的 COM 和多线程经验。但基本上,围绕任何 COM 组件设计自定义包装器组件是一种很好的做法,只是为了保护您的 COM 类所需的资源。

Delphi 最大的弱点往往是字符串处理和大数组的处理。(尤其是包含对象的数组;使用记录代替。)字符串本身在 Delphi 中很快,但在 Delphi 中的字符串函数不是很优化。例如,我曾经有一个包含一些 XML 数据的字符串。它有很多布尔字段,拼写为“True”和“False”,需要将它们转换为“true”和“false”。一个简单的字符串替换大约需要 15 秒来替换所有这些值。我重写了它,使用 MSXML 将 XML 加载到 DOM 文档中,使用 XPath 选择所有布尔节点,遍历这些节点以用正确的文本替换所有值,然后将 XML 放回单个字符串中。突然间,它能够在两秒钟内做到同样的事情!对于看起来更慢的东西来说,这是一个巨大的性能增益。原因?Delphi 在处理字符串时,往往会在处理过程中多次复制字符串。或者它需要为字符串分配越来越多的内存以增加大小。这需要时间,在 C++ 等其他语言中不会浪费时间。

于 2009-06-08T15:18:48.817 回答
0

COM 重要的是您的应用程序支持什么“公寓模型”。Delphi 中最常用的是单线程单元模型,也称为“单元线程”,其中 COM 调用与您的应用程序主消息队列同步。使用此模型,您一次只能处理一个 COM 调用,并且 COM 对象不支持来自其他线程的调用。

但是,您可以将您的 COM 单元模型初始化为多线程,这样做您必须确保对共享资源的访问正确同步 - 您启动的每个线程都必须通过调用加入多线程单元CoInitializeEx(nil, COINIT_MULTITHREADED);

当您公开 DCOM 接口时,事情变得非常有趣,因为 RPC 子系统有一个线程池用于服务请求,它可以直接访问多线程单元中的所有 COM 对象,从而实现高性能服务器。如果您使用的是单元线程,您将不得不经历消息队列的瓶颈,并且单个线程一次只能调度一个 COM 调用。

Chris Bensen 也写了一篇很好的博客文章,其中包含一些代码示例。

于 2009-06-09T22:13:41.067 回答
0

做了一些研究并得到了一些指示,特别是我的第一个问题:

Delphi中的事件是串行的还是并行的,也就是说,如果我在一个正在执行的时候得到一个新的事件——会发生什么?它是在某种自动线程上并行运行,是被忽略还是排队?如果它被排队,在应用程序崩溃之前我可以在队列中有多少?

好吧,显然事件与其他所有事件一样是同步的,或者我应该说是串行的。在处理一个事件时,您无法获得更多事件,因为该事件本质上是一个函数调用。

在事件处理程序中,处理了一些图形组件。由于该事件是在另一个线程上引发的,这很糟糕。我要么需要对位于创建图形的线程上的图形进行一些更新机制,要么在事件中进行线程切换。

此外,测试表明,实际上是图形更新所花费的时间越来越长,因此重构图形处理听起来是一个不错的尝试途径。

于 2008-12-18T07:39:44.923 回答