代码之家  ›  专栏  ›  技术社区  ›  Vaibhav

多线程设计最佳实践

  •  3
  • Vaibhav  · 技术社区  · 17 年前

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

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

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

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

    4 回复  |  直到 12 年前
        1
  •  6
  •   C1pher    12 年前

    选项3是最好的:

    使用异步IO。

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

    这正是AsyncIO的设计目的-让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的情况下,“完成回调”实际上是在线程池线程中触发的,而不是在主线程中,因此您仍然需要锁定任何共享资源,但它仍然为您节省了管理线程的所有麻烦。

        2
  •  3
  •   Derek Park    17 年前

    有两件事要考虑。

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

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

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

    2。您计划启动多少线程?

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

        3
  •  0
  •   Hugo    17 年前

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

    回答您的请求也可能会有延迟。您可以尝试确保所有方法都有给定数量的未完成的服务器请求。

        4
  •  0
  •   Will    17 年前

    得到 Parallel Fx . 看看blockingcollection。使用一个线程向它提供一批记录,使用1到n个线程将收集中的记录提取到服务中。您可以控制收集的速率,以及调用Web服务的线程数。通过配置部分使其可配置,并通过提供集合操作委托使其通用,您将拥有一个很好的小批处理程序,可以重用到您的心脏内容中。

    推荐文章