Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 多线程设计最佳实践_.net_Multithreading - Fatal编程技术网

.net 多线程设计最佳实践

.net 多线程设计最佳实践,.net,multithreading,.net,Multithreading,考虑这个问题:我有一个程序,它应该从一个数据库中获取(比如)100条记录,然后对于每一条记录,它应该从一个web服务中获取更新的信息。在这种情况下,有两种方法可以引入并行性: 我在一个新线程上启动对web服务的每个请求。同时线程的数量由一些外部参数控制(或以某种方式动态调整) 我创建了较小的批处理(假设每个批处理10条记录),并在一个单独的线程上启动每个批处理(以我们的示例为例,10条线程) 这是一个更好的方法,你为什么这么认为? < P> >两件事要考虑。 1.处理一个记录需要多长时间? 如果

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

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

  • 我创建了较小的批处理(假设每个批处理10条记录),并在一个单独的线程上启动每个批处理(以我们的示例为例,10条线程)


  • <>这是一个更好的方法,你为什么这么认为?

    < P> >两件事要考虑。

    1.处理一个记录需要多长时间? 如果记录处理非常快,那么将记录传递给线程的开销可能会成为瓶颈。在这种情况下,您可能希望捆绑记录,这样就不必如此频繁地传递它们

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

    2.您计划启动多少线程?
    如果您不使用线程池,我认为您要么需要手动限制线程的数量,要么需要将数据分成大块。如果记录数量过多,为每条记录启动一个新线程将导致系统崩溃。

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

    回答您的请求可能也会有延迟。您可以尝试确保始终有一定数量的未完成请求发送到服务器。

    获取请求。看看BlockingCollection。使用一个线程向其提供成批记录,并使用1到n个线程从集合中提取记录以提供服务。您可以控制向集合馈送的速率,以及调用web服务的线程数。通过ConfigSection将其设置为可配置的,并通过向collection Action委托提供信息使其成为通用的,这样您就有了一个很好的小批处理程序,您可以充分利用它。

    选项3是最好的:

    使用异步IO

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

    这正是异步IO的设计目的——让windows网络堆栈(或.net framework或其他什么)担心所有的等待,只需使用一个线程来调度和“获取”结果

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

    编辑:


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

    您真的需要使用状态对象传递请求,还是可以将请求用作闭包绑定变量?是的,这些都是有用的注意事项。因为这是调用公共域webservice,所以我想我们可能需要运行一些测试,看看开销是否超过了作业本身(我对此表示怀疑)。是的,我们肯定会考虑使用ThreadPool。动态/可配置,因为最佳数量取决于环境和瓶颈实际是什么。这听起来像是一项针对客户的工作。把作业排成一列,让.net来处理其余的工作。@Patrick好吧,我在考虑线程池的动态控制。但我想我正在试图弄清楚这两种方法之间是否有任何性能差异(实际上,ThreadPool可以在这两种方法中使用)。如果不是绩效,是否有任何最佳实践值得遵循。
    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();
    }