多线程是提高应用程序性能的答案吗?

4
我有一个控制台应用程序,它执行以下操作:
  1. 读取输入文件。输入文件按行排列,包含成千上万行数据。
  2. 对输入文件进行预处理并转换为中间文件。中间文件具有相同数量的行。
  3. 逐行从中间文件中读取一行,形成Web请求并将其发送到Web服务器。
  4. 逐个请求从Web服务器读取响应,对其进行处理(解析)并将其写入输出文件。输出文件与输入文件具有相同数量的行。
目前,该应用程序可以正常工作,但速度非常慢。我想提高应用程序的性能,使其更快。
  1. 有人能告诉我可能在这种情况下使用的各种方法吗?

  2. 如果多线程是解决问题的答案,有人能建议几个起点吗?

编辑: 所有请求都发送到同一服务器。就服务器而言,我对其容错能力知之甚少(如果必要,我可能会尝试限制发送到服务器的请求数)。

3
所有请求都发往同一台Web服务器吗?该服务器能否有效地处理多个并行请求? - Jon Skeet
所有请求都发送到同一台服务器。就服务器而言,我对其容错能力知之甚少或者根本不了解。 - futurenext110
3
在我看来,为了对此做出合格/有见地的回答,你需要“找到答案”。 - Marc Gravell
1
我也会考虑批处理Web请求。根据问题中有限的信息,我猜串行延迟是您最大的瓶颈,但首先要进行分析。 - Tim M.
基本上,如果您一次只发送一个请求而不进行线程处理,则会将大量延迟依次堆叠。因此,线程处理绝对值得研究,但您也可以考虑在每个请求中发送多个记录。因此,与其发送1000个微小的请求,不如发送10个包含100个记录的批次。这假定服务器可以处理每个请求中的多个记录。 - Tim M.
显示剩余4条评论
3个回答

2

要线程还是不要线程?这是个问题...

关于多线程的简单而正确的回答是:是的,只要 1)算法可行,2)它涉及 I/O-bound 操作或者你有几个 CPU-bound 操作的核心。

第一点:可行性

  1. 为了执行步骤 2,您必须完成步骤 1。此时没有多线程
  2. 步骤 3 需要完成步骤 2,但涉及独立的按行活动(每行一个请求)。BINGO!
  3. 步骤 4 需要完成步骤 3 中的所有请求。多线程在此结束。

第二点:操作类型

Web 请求是 I/O-bound 操作。您可以获得最大的好处。由于您正在对同一服务器执行请求,无论是否容错,都必须限制查询速率。需要适当地调整并发请求的数量,但如果在代码中使用常量(如 const int NUMBER_OF_THREADS = 4;),则有一个良好的起点。

建议

使用信号量来处理并发请求。

像以前一样从文件读取并转换为中间文件开始程序。

完成后,创建一个固定大小的数组(您说最终文件具有相同数量的行,因此可以分配它),然后为每行启动一个循环:

  1. 获取一个信号量,它初始化为 NUMBER_OF_THREADS 常量,这将允许主线程激活 4 个并发线程。
  2. 通过传递行、目标数组和索引来启动线程(如果列表是类成员,则实际上不需要传递所有参数)。

循环结束后,在 AutoResetEvent 上等待,我会简要讨论一下。

在线程中,执行以下操作:

  1. 执行 Web 请求
  2. 处理结果
  3. 将结果保存到相应的目标数组行中
  4. 使用 Interlocked.Increment() 方法增加一个跨线程共享的变量(此处未讨论)
  5. if 共享变量 equals 行数,则 then 发布我提到的 AutoResetEvent,以便解锁主线程

调整

从 4 个并发线程开始。尝试将它们增加到 8 并查看性能。我建议您不要超过 12 个线程,但其他人可能会说那可能太多了...这只是尝试和失败。


0

在读取文件的同时,您也在写入文件。首先想到的是使用大块(BufferedReader)读取文件,以确保磁盘不会过多寻道。

至于您的服务器,在我的经验中,大多数Web服务器对每秒多个请求都相当宽容。如果您自己托管服务器,我建议简单地使用异步Web请求并找出发生了什么... 但是,从听起来的声音来看,您正在创建一个简单的网络爬虫,在这种情况下,我强烈建议要有耐心:在别人的服务器上引起麻烦绝不是一个好主意。为了给您一个指示:我们的网络爬虫总是限制每个服务器每秒1个请求。


0

我将创建一个基于内部消息队列和生产者-消费者链的应用程序。

* -> * -> * -> *

其中每个*线程执行以下操作:读取、处理、查询WS、后处理。当*节点的生产队列已满或消费队列为空时,它会进入睡眠状态。

如果需要,在每个点上可以创建多个消费者(最可能在WS处理程序中),如下所示:

         / * \ 
* -> * ->  *  -> *
         \ * /

架构准备好后,您可以通过更改每个点的队列大小来调整应用程序。

此外 - 您可以使用线程池来处理每个处理节点,从而确保充分利用处理器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接