多线程设计最佳实践

时间:2008-08-13 19:03:21

标签: .net multithreading

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

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

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

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

4 个答案:

答案 0 :(得分:6)

选项3是最好的:

使用Async IO。

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

这正是Async 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 :(得分:2)

需要考虑两件事。

1。处理记录需要多长时间?

如果记录处理非常快,将记录移交给线程的开销可能成为瓶颈。在这种情况下,您可能希望捆绑记录,这样您就不必经常将它们移除。

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

2。你打算开始多少线程?

如果您没有使用线程池,我认为您需要手动限制线程数,或者您需要将数据分成大块。如果记录数量很大,则为每条记录启动一个新线程将使您的系统崩溃。

答案 2 :(得分:0)

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

回复您的请求可能会有延迟。您可以尝试确保始终向服务器提供一定数量的未完成请求。

答案 3 :(得分:0)

获取Parallel Fx。看看BlockingCollection。使用线程为其提供批量记录,并使用1到n个线程将记录从集合中提取出来进行维护。您可以控制收集的速率以及调用Web服务的线程数。通过ConfigSection使其可配置,并通过提供集合Action代理使其成为通用的,并且您将有一个很好的小批量,您可以重复使用您的内容。