4

我有一个控制台应用程序,它执行以下操作:

  1. 读取输入文件。输入文件具有运行到数千行的逐行数据
  2. 预处理输入文件并转换为中间文件。中间文件的行数相等。
  3. 一次从中间文件中读取一行,形成一个 Web 请求并将其发送到 Web 服务器。
  4. 一次从网络服务器读取每个请求的响应,处理(解析)它并将其写入输出文件。输出的行数也与输入文件相同。

现在,目前该应用程序运行良好,但速度很慢。我想提高应用程序的性能,使其更快一些。

  1. 有人可以告诉我在这种情况下可能使用的各种方法吗?

  2. 如果多线程是问题的答案,有人可以建议一些起始指针吗?

编辑:所有请求都将发送到同一台服务器。就服务器而言,我对其容忍度知之甚少或一无所知(如果归结为这一点,我可能会考虑限制对服务器的请求线程数)。

4

3 回答 3

2

穿线还是不穿线?就是那个问题...

对问题的多线程部分的一个简单而正确的答案是:是的,只要 1)根据算法是可行的,并且 2)它涉及 I/O 绑定操作,或者您在 CPU 绑定操作中有多个内核

第一点:可行性

  1. 为了执行第 2 步,您必须完成第 1 步。还没有多线程
  2. 第 3 步需要完成第 2 步,涉及独立的逐行活动(每行一个请求)。答对了!!
  3. 第 4 步需要在第 3 步完成所有请求。多线程到此结束。

第二点:操作类型

Web 请求是 I/O 绑定操作。你得到最大的利益。由于您正在向同一台服务器执行请求,无论是否容错,您都必须限制查询速率。需要适当调整并发请求的数量,但是如果您在代码中使用常量(如const int NUMBER_OF_THREADS = 4;),那么您有一个很好的起点。

提案

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

像以前一样,通过读取文件并转换为中间文件来启动程序。

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

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

循环之后,等待AutoResetEvent我将简要讨论的

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

  1. 执行网络请求
  2. 处理结果
  3. 将结果保存到对应的目标数组行
  4. 使用方法增加跨线程共享的变量(此处未讨论)Interlocked.Increment()
  5. if共享变量equals行数,then释放AutoResetEvent我提到的这样你就可以解锁主线程

调音

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

于 2013-01-23T08:49:45.450 回答
0

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

* -> * -> * -> *

其中每个*都是一个线程:读取、处理、查询 WS、后处理。当*生产队列已满或消费队列为空时,节点会休眠。

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

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

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

此外 - 您可以使用线程池来处理每个处理节点,因此确保您的处理器使用最多。

于 2013-01-23T08:44:23.267 回答
0

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

至于您的服务器,根据我的经验,大多数 Web 服务器每秒都可以容忍多个请求。如果您自己托管服务器,我会简单地使用异步网络请求并弄清楚会发生什么......但是,从它的声音来看,您正在创建一个简单的网络爬虫,在这种情况下,我强烈建议您耐心等待:造成麻烦别人的服务器从来都不是一个好主意。给您一个提示:我们的网络爬虫始终限制为每台服务器每秒 1 个请求。

于 2013-01-23T08:38:08.597 回答