0

将网页源下载到备忘录组件中的最快方法是什么?我使用 Indy 和 HttpCli 组件。

问题是我有一个包含 100 多个站点的列表框,我的程序将源下载到备忘录并解析该源以获取 mp3 文件。它有点像谷歌音乐搜索程序;它使用谷歌查询使谷歌搜索更容易。

我开始阅读导致我的问题的线程:我可以在具有解析功能的线程中创建一个 IdHttp 实例并告诉它解析列表框中的一半站点吗?

所以基本上当用户点击解析时,主线程应该做:

for i := 0 to listbox1.items.count div 2 do
    get and parse

,另一个线程应该这样做:

for i := form1.listbox1.items.count div 2 to form1.listbox1.items.count - 1 do
    get and parse.

,所以他们会form1.listbox2同时添加解析的内容。或者在主线程中启动两个 IdHttp 实例是否更容易?一个用于前半个站点,另一个用于第二个站点?

为此:我应该使用 Indy 还是 Synapse?

4

3 回答 3

9

我将创建一个可以读取单个 url 并处理其内容的线程。然后,您可以决定要同时触发多少个线程。您的计算机将允许相当多的连接,因此如果这 100 个站点具有不同的主机名,那么同时运行 10 个或 20 个也不成问题。太多是矫枉过正,但太少是浪费处理器时间。

您可以通过使用单独的线程进行下载和处理来进一步调整此过程,以便您可以拥有多个线程不断下载内容。下载不是非常密集的处理器。它基本上是在等待响应,因此您可以轻松拥有相对大量的下载线程,而其他几个工作线程可以从结果池中获取项目并进行处理。
但是拆分下载和处理会使它变得更加复杂,而且我认为您还没有应对这个挑战。

因为目前,您遇到了一些其他问题。起初,在线程中使用 VCL 组件是不可行的。如果您需要来自线程中列表框的信息,您将需要在线程中使用 Synchronize 以对主线程进行“安全”调用,或者您必须在启动线程之前传递所需的信息。后者效率更高,因为使用 Synchronize 执行的代码实际上在主线程中运行,从而降低了多线程效率。

但我的注意力却被第一行吸引了,“将网页源下载到备忘录组件中”。不要那样做!不要将这些结果加载到备忘录中进行处理。自动处理最好在内存中完成,在视觉控制之外。使用字符串、流,甚至字符串列表来处理文本比使用备忘录要快得多。
字符串列表也有一些开销,但它使用相同的索引行结构(TMemoStrings,它是备忘录的 Lines 属性,和 TStringList 都有相同的祖先),所以如果你有使用这个的代码,将其转换为 TStringList 将非常容易。

于 2011-11-06T19:57:52.370 回答
5

我建议在线程中进行所有解析,根本不要让主线程进行任何解析。主线程应该只管理 UI。不要从 TMemo 解析 HTML,让每个线程下载到 TStream 或 String,然后直接从中解析。使用 TIdSync 或 TIdNotify 将解析结果发送到 UI 进行显示(如果速度很重要,请使用 TIdNotify)。在解析逻辑中涉及 UI 组件会减慢它的速度。

于 2011-11-06T19:57:33.563 回答
4

Indy 或 Synapse 都支持多线程。我建议使用 Synpase,它比 Indy 轻得多,并且足以满足您的目的。不要忘记Microsoft 提供的HTTP API 。

简单的实现:

  • 每个 URI 一个线程;
  • 每个线程使用一次 HTTP 通信获取数据;
  • 然后每个线程解析数据;
  • 然后用于Synchronize刷新 UI。

也许是我最喜欢的:

  • 定义要使用的最大线程数(例如 8 个);
  • 这些线程中的每一个都将维护一个远程连接(这是 HTTP/1.1 的目的,并且可以真正对速度产生影响);
  • 所有请求都由这些线程一一检索——不要为线程预先分配 URL,而是在线程完成一个时从全局列表中检索一个新 URL(每个 URL 并不总是花费相同的时间);
  • 线程可能会等待,直到将任何其他 URI 添加到全局列表中(Sleep(100)例如使用 a 或信号量);
  • 然后使用专用的 GDI 消息 () 在主 GUI 线程中解析和更新 UI WM_USER+...- 恕我直言,解析会很快(请记住 UI 刷新可能很慢 -BeginUpdate-EndUpdate例如查看方法) - 我发现 GDI message (带有相关的 HTML 数据)比使用Synchronizewhich 阻塞后台线程更有效;
  • 另一种选择是在后台线程中进行解析,就在从其 URI 检索数据之后——也许不值得(仅当您的解析器很慢时),如果您的解析器/数据处理器可能会遇到多线程问题不是 100% 线程安全的。

第二个是流行的所谓“下载管理器”是如何实现的。

当您处理多线程时,您必须“保护”您的共享资源(例如列表)。使用 aTCriticalSection访问任何全局列表(例如 URI 列表),并尽快释放锁。

并尝试使用多台计算机和网络、并发访问、不同的操作系统来测试您的实现。调试多线程应用程序可能很困难,所以实现越简单越好:这就是为什么我建议将下载部分设为多线程的原因,但让主线程处理数据(不会很大,所以应该快点)。

于 2011-11-07T06:32:30.653 回答