zoukankan      html  css  js  c++  java
  • TCP应用

    本文作为 .Net 并行计算 的第二篇

    • 名词解释

           任务并行是指一个或者多个独立的任务同时运行。任务并行类似于多线程或者ThreadPool 工作项。但是抽象的级别更高

    •  并行任务的2个有点 1。系统使用的率更高 2.可以使用更多的编程控件
    • 创建和运行任务

           1.隐式创建和运行任务。Parallel.Invoke方法提供了一种简便方式,可同时运行任意数量的任意语句。只需为每个工作项传入 Action 委托即可 大家可以想一下了例子的运行结果是什么? 会是输出 时间2000 吗 。如果你这么想就错了。笔者的电脑上输出的结果为 时间1005 (可能在你的电脑上的结果和我的不一定相同)因为他并不是一个顺序执行的过程。

    1
    2
    Stopwatch watch1 = Stopwatch.StartNew();<br>            Parallel.Invoke(() => { Thread.Sleep(1000); }, () => { Thread.Sleep(1000); });
    Console.WriteLine("时间"+watch1.ElapsedMilliseconds);

         2.显示创建和运行任务

           不返回值的任务由 System.Threading.Tasks.Task 类表示。返回值的任务由 System.Threading.Tasks.Task<TResult>类表示,该类从Task继承任务对象处理基础结构详细信息,并提供可在任务的整个生存期内从调用线程访问的方法和属性。下面的例子演示创建一个不返回的任务,和一个返回值的任务

          

                var task = new Task(() => { Thread.Sleep(1000); });
                task.Start();
                var task1 = new Task<int>(() => { Thread.Sleep(1000); return 100; });
                task1.Start();
                Console.WriteLine(task1.Result);
                Console.ReadLine();
    •  延续任务

            我们经常会面对这样一个场景。在一个操作完成后调用另一个的操作并将结果传递其中,我们日常编程中我们一般使用回调来弄。那么我们要怎么样在并行中来处理这个场景了。并行库中的“延续任务”提供了同样功能。  延续任务是一个异步任务,由另一个任务(称为前面的任务)在完成时调用。  下面的例子将使用TaskA.ContinueWith演示创建延续

                Task<int> TaskA = new Task<int>(() => { return DateTime.Now.Year; });
                Task<String> TaskB = TaskA.ContinueWith((a) => { return String.Format("今年是{0}年", a.Result); });
                TaskA.Start();
                Console.WriteLine(TaskB.Result);

         在上面这个例子中TaskB 必须要TaskA 完成之后。才能得到正确结果。这只是延续的一个非常简单的例子,当然你也可以创建一个多任务延续你可以在多个,或者全部的任务完成之后来运行 这里我还是以上面的取消年月为例子给大家演示一下
            

    复制代码
       Task<int>[] tasks = new Task<int>[2];
                 tasks[0]= new Task<int>(() => { return DateTime.Now.Year; });
                 tasks[1] = new Task<int>(() => { return DateTime.Now.Month; });
                 var continuation = Task.Factory.ContinueWhenAll(
                                      tasks,
                                      (antecedents) =>
                                      {
                                          string r = string.Format("现在是{0}年{1}月", antecedents[0].Result, antecedents[1].Result);
                                          Console.WriteLine(r);
                                      });
                 tasks[0].Start();
                 tasks[1].Start();
                 continuation.Wait();
    复制代码
    •  嵌套任务和子任务

            子任务(或嵌套任务)是在另一个任务(称为父任务)的用户委托中创建的Task实例。 子任务可分离或附加。  分离的子任务是独立于其父任务执行的任务。  附属子任务是使用 TaskCreationOptions.AttachedToParent 选项创建的嵌套任务。  一个任务可以创建任意数量的嵌套和分离子任务,该数量仅受系统资源限制

    复制代码
     var parent = Task.Factory.StartNew(() =>
                {
                    Console.WriteLine("父任务");
    
                    var child = Task.Factory.StartNew(() =>
                    {
    
                        Thread.Sleep(5000);
                        Console.WriteLine("子任务");
                    });
                });
    
                parent.Wait();
                Console.WriteLine("大家都完了.");
    复制代码

       大家想不想知道,上面的执行结果是怎么样了 "父任务 子任务 大家都完了" 还是“父任务  大家都完了 子任务" 你可以把这段代码考到vs中,你就会发现是后者从上面的例子中我们可以得出以下结论 父任务是不等待子任务完成的  他还有以下特性 父任务不传播子任务引发的异常。父级状态不依赖于子状态。

    • 任务取消

         1.简单从委托中返回。其实在多数情况下这样已经够了。但是这样取消的任务实例不会转为Canceled状态而是转为RanToCompletion状态

         2.引发 OperationCanceledException 

        

    复制代码
               var tokenSource = new CancellationTokenSource();
                CancellationToken ct = tokenSource.Token;
    
                var task = Task.Factory.StartNew(() =>
                {
                    ct.ThrowIfCancellationRequested();
                
                bool moreToDo=true;
                while (moreToDo)
                {
                    if (ct.IsCancellationRequested)
                    {
                        ct.ThrowIfCancellationRequested();
                    }
                }
    
                }, tokenSource.Token);
    
                tokenSource.Cancel();
                try
                {
                    task.Wait();
                }
                catch (AggregateException e)
                {
                    foreach (var v in e.InnerExceptions)
                        Console.WriteLine(e.Message + " " + v.Message);
                }
    复制代码


       下一篇将讲一下并行Linq 欢迎交流拍砖

       

    WinSocket同时接入量的疑惑(求解...)

            在写TCP应用的时候一般都通过Accept来接入连接的接入,但对于Socket来说这个Accept同时能处理多大的量一般都没有明确说明,在应用中主要根据自己的需要设置Listen的队列数量.那Listen(1000)是不是就能说明同时刻1000个连接进来都能被Accept到呢?通过测试的结果来看windows下是不能的....Linux下则可以.

    测试代码

    • C#
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      mSocket.Bind(new IPEndPoint(IPAddress.Any,80));
      mSocket.Listen(1000);
      int i = 0;
      while (true)
      {
          Socket http= mSocket.Accept();
          System.Threading.Thread.Sleep(200);
          i++;
          Console.WriteLine("Accept:{0} ", i);
           
      }
    • win C++
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      iResult = listen(ListenSocket, 1000);
      if (iResult == SOCKET_ERROR) {
          printf("listen failed with error: %d ", WSAGetLastError());
          closesocket(ListenSocket);
          WSACleanup();
          return 1;
      }
      int i=0;
      while(true)
      {
          // Accept a client socket
          ClientSocket = accept(ListenSocket, NULL, NULL);
          i++;
          if (ClientSocket == INVALID_SOCKET) {
              printf("accept failed with error: %d ", WSAGetLastError());
              closesocket(ListenSocket);
              WSACleanup();
              return 1;
          }
          iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
          printf("accept: %d ", i);  
      }
    • linux c++
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
      {
          perror("bind");
          return 1;
      }
      listen(server_sockfd,1000);
      sin_size=sizeof(struct sockaddr_in);
      int i=0;
      while(1)
      {
          i++;
          if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0)
          {
              cout<<"accept error";
              return 1;
          }
           len=recv(client_sockfd,buf,BUFSIZ,0);
          cout << "Accept:" << i<<"Receive:"<<len;
       
      }

            通过AB开启500个用户压相应的程序,C#,WIN C++都会导致AB出现apr_socket_recv: Connection refused (111).但Linux c++这代码是完全正常,AB所有请求的连接都通过被Linux c++接入.

            以上程序上所有Listen都是1000, 按理500个用户同时接入不应该存在被拒绝的情况,因为请求的连接数并没达队列溢出的情况.但测试的结果很明确地说明的问题所在,winsocket下无法同时接入这个量的连接,其实在测试过程250个用户同时接入winsocket就存在拒绝接入的情况,当然服务是不会有影响只是有些连接无法被接入.

    总结

            通过测试可以确认是winsocket的限制,windows则没有因为IIS是可以抵抗这么多用户同时接入的.其实对于普通服务来说同时200个用户接入已经是一个不小的量了,因为持续这个量的处理每秒接入量可以达到1-2W.但感觉奇怪的是为什么Listen(1000)在winsocket下没有起到作用呢?找了很多资料都没找到具体原因,如果有熟悉winsocket还有其他参数设置的话希望能分享一下...

     

             

      

     
     
    分类: .Net
  • 相关阅读:
    pthread线程内存布局
    用户空间实现线程 内核实现线程 线程的调度
    堆 虚拟内存
    Operating System-Thread(3)用户空间和内核空间实现线程
    Linux进程地址空间与虚拟内存
    虚拟地址
    物理内存,虚拟内存,进程地址空间
    CPU中MMU的作用
    进程地址空间与虚拟存储空间的理解
    虚拟地址空间
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3488332.html
Copyright © 2011-2022 走看看