Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何更快地下载?_Delphi_Indy_Synapse - Fatal编程技术网

Delphi 如何更快地下载?

Delphi 如何更快地下载?,delphi,indy,synapse,Delphi,Indy,Synapse,将网页源下载到备忘录组件中的最快方法是什么?我使用Indy和HttpCli组件 问题是我有一个列表框,里面有100多个站点,我的程序将源文件下载到备忘录中,并解析源文件中的mp3文件。它有点像谷歌音乐搜索程序;它使用谷歌查询使谷歌搜索更容易 我开始阅读关于线程的文章,这引出了我的问题:我可以在一个具有解析功能的线程中创建一个IdHttp实例,并告诉它解析列表框中的一半站点吗 因此,基本上,当用户单击parse时,主线程应该执行以下操作: for i := 0 to listbox1.items.

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

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

我开始阅读关于线程的文章,这引出了我的问题:我可以在一个具有解析功能的线程中创建一个IdHttp实例,并告诉它解析列表框中的一半站点吗

因此,基本上,当用户单击parse时,主线程应该执行以下操作:

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.
,而另一个线程应执行以下操作:

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?

我建议在线程中执行所有解析,而不要让主线程执行任何解析。主线程应该只管理UI。不要从TMemo解析HTML,让每个线程下载到一个TStream或字符串,然后直接从中解析。使用TIdSync或TIdNotify将解析结果发送到UI以供显示(如果速度很重要,请使用TIdNotify)。在解析逻辑中包含UI组件会降低速度。

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

您可以通过使用单独的线程进行下载和处理来进一步调整此过程,这样您就可以有多个线程不断下载内容。下载不是很需要处理器。它基本上是在等待响应,因此您可以轻松地拥有相对大量的下载线程,而其他几个工作线程可以从结果池中获取项目并对其进行处理。
但是,将下载和处理分开会使它变得更复杂一点,我认为你还不能胜任这个挑战

因为现在,你还有一些其他的问题。首先,在线程中使用VCL组件是不可行的。如果需要线程中列表框的信息,则需要在线程中使用Synchronize对主线程进行“安全”调用,或者在启动线程之前必须传递所需的信息。后者效率更高,因为使用Synchronize执行的代码实际上是在主线程中运行的,这会降低多线程的效率


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

Indy或Synapse都是多线程就绪的。我建议使用Synpase,它比Indy轻得多,足以满足您的需要。不要忘记Microsoft提供的

简单实现:

  • 每个URI一个线程
  • 每个线程使用一个HTTP通信获取数据
  • 然后每个线程解析数据
  • 然后使用
    同步
    刷新UI
也许是我最喜欢的:

  • 定义要使用的最大螺纹数(例如8)
  • 这些线程中的每一个都将维护一个远程连接(这是HTTP/1.1的目的,可以真正改变速度)
  • 所有请求都由这些线程逐个检索-不要将URL预先分配给线程,而是在线程完成一个URL后从全局列表中检索一个新的URL(每个URL并不总是占用相同的时间)
  • 线程可以等待,直到任何其他URI被添加到全局列表中(使用
    Sleep(100)
    或信号量等)
  • 然后使用专用的GDI消息(
    WM_USER+…
    )在主GUI线程中解析和更新UI-解析会很快(记住UI刷新可能会很慢-例如查看
    BeginUpdate EndUpdate
    方法)-我发现一条GDI消息(带有关联的HTML数据)比使用阻止后台线程的
    同步
    更有效
  • 另一种选择是在后台线程中进行解析,就在从URI中检索数据之后——可能不值得(只有在解析器速度慢的情况下),如果解析器/数据处理器不是100%线程安全的,则可能会出现多线程问题
第二个问题是所谓的“下载管理器”是如何实现的

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


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

我建议您阅读有关同步的文档