考虑这个问题:我有一个程序,它应该从数据库中获取(比方说)100 条记录,然后对于每一条记录,它应该从 Web 服务获取更新的信息。在这种情况下有两种引入并行性的方法:

  1. 我在新线程上启动对 Web 服务的每个请求。并发线程的数量由某些外部参数控制(或以某种方式动态调整)。

  2. 我创建较小的批次(假设每个批次有 10 个记录)并在单独的线程上启动每个批次(以我们的示例为例,10 个线程)。

哪种方法更好,您为什么这么认为?

有帮助吗?

解决方案

选项 3 是最好的:

使用异步 IO。

除非您的请求处理复杂且繁重,否则您的程序将花费 99% 的时间来等待 HTTP 请求。

这正是异步 IO 的设计目的 - 让 Windows 网络堆栈(或 .net 框架或其他)担心所有等待,只使用单个线程来分派和“获取”结果。

不幸的是,.NET 框架使它成为一个令人头疼的问题。如果您只使用原始套接字或 Win32 api,那就更容易了。无论如何,这是一个使用 C#3 的(经过测试的!)示例:

using System.Net; // need this somewhere

// need to declare an class so we can cast our state object back out
class RequestState {
    public WebRequest Request { get; set; }
}

static void Main( string[] args ) {
    // stupid cast neccessary to create the request
    HttpWebRequest request = WebRequest.Create( "http://www.stackoverflow.com" ) as HttpWebRequest;

    request.BeginGetResponse(
        /* callback to be invoked when finished */
        (asyncResult) => { 
            // fetch the request object out of the AsyncState
            var state = (RequestState)asyncResult.AsyncState; 
            var webResponse = state.Request.EndGetResponse( asyncResult ) as HttpWebResponse;

            // there we go;
            Debug.Assert( webResponse.StatusCode == HttpStatusCode.OK ); 

            Console.WriteLine( "Got Response from server:" + webResponse.Server );
        },
        /* pass the request through to our callback */
        new RequestState { Request = request }  
    );

    // blah
    Console.WriteLine( "Waiting for response. Press a key to quit" );
    Console.ReadKey();
}

编辑:

对于 .NET,“完成回调”实际上是在 ThreadPool 线程中触发的,而不是在主线程中触发的,因此您仍然需要锁定任何共享资源,但它仍然为您省去了管理线程的所有麻烦。

其他提示

有两件事需要考虑。

1.处理一条记录需要多长时间?

如果记录处理速度非常快,则将记录移交给线程的开销可能会成为瓶颈。在这种情况下,您可能希望将记录捆绑在一起,这样就不必频繁地传递它们。

如果记录处理运行时间相当长,则差异可以忽略不计,因此更简单的方法(每个线程 1 条记录)可能是最好的。

2.您计划启动多少个线程?

如果您不使用线程池,我认为您要么需要手动限制线程数量,要么需要将数据分成大块。如果记录数量变大,为每条记录启动一个新线程将使系统崩溃。

运行该程序的计算机可能不是瓶颈,因此:请记住,HTTP 协议有一个 keep-alive 标头,它允许您在同一套接字上发送多个 GET 请求,从而避免 TCP/IP 握手。不幸的是我不知道如何在.net 库中使用它。(应该是可以的。)

答复您的请求也可能会有所延迟。您可以尝试确保始终对服务器有给定数量的未完成请求。

获取 并行效果. 。查看 BlockingCollection。使用一个线程向其提供批量记录,并使用 1 到 n 个线程从集合中提取记录以供服务。您可以控制提供集合的速率以及调用 Web 服务的线程数。通过 ConfigSection 使其可配置,并通过提供集合 Action 委托使其通用,您将拥有一个漂亮的小批处理程序,您可以根据自己的喜好重用它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top