【问题标题】:Asynchronous delegates vs Threads异步委托与线程
【发布时间】:2012-07-13 05:43:15
【问题描述】:

用异步委托(回调)替换线程(不是 ThreadPool 线程)。

我的场景:为每个客户端生成一个 Thread/del.beginInvoke()。

据我所知,

原因

  1. 需要通过回调通知/在回调中再次调用委托
  2. 避免线程开销,(委托使用线程池线程)
  3. 传递参数(避免转换为对象)并需要方法的返回值。

如果上述原因有误,请纠正我。

  1. 还有其他原因吗?
  2. 什么情况下我需要用异步委托做一些事情 线程不能?
    3.性能?

例子

    public delegate void SendCallbackType();

    SendCallbackType senderdel= new SendCallbackType(SendData);

    public void StartSend() // This method Could be Called more than 700 times (Thread per Client)
    {
        senderdel.BeginInvoke(SendCallback,null);
                   // (or)
        Thread t = new Thread(new ThreadStart(ThreadSend));
        t.IsBackground = true;
        t.Start();
    }

  //Async Delegate
    void SendData()
    {
         string data = QueData.DeQueue();
         RaiseOnData(data); // Raise to event.
    }
    void SendCallback(IAsyncResult ar)
    {
        senderdel.BeginInvoke(SendCallback, null);
    }

 //Thread
  void ThreadSend()
  {
      while (true)
      {
         string data = QueData.DeQueue();
         RaiseOnData(data); // Raise to event.
      }
   }

从上面哪个选项是最好的。表现 ?

【问题讨论】:

    标签: c# asynchronous delegates


    【解决方案1】:

    你的推理是正确的。异步委托使用线程池中的线程,因此与手动创建线程相比,它们应该更快。不过在 ASP.NET 应用程序中要小心。因为您将占用 ASP.NET 通常用于服务请求的工作线程,并且您的应用程序可能很快就会耗尽服务能力。

    异步委托适用于 CPU 密集型任务。对于 I/O 密集型任务(例如读取流、数据库调用和 Web 服务调用),您应该使用相应类(Stream、SqlConnection、WebClient...)直接提供的 BeginXXX、EndXXX 方法。这样,您在冗长的 I/O 操作期间根本不会使用任何线程。您正在使用I/O Completion Ports,这在 I/O 绑定任务方面是最好的。与任何线程和线程池相比,它的性能和资源成本都要高出几个数量级。

    总结一下:

    • 对于 I/O 密集型任务,请使用 I/O 完成端口。如果 I/O 密集型任务被包装在一个编写不佳的库中,而该库无法提供这种可能性,请使用 .NET 4.0 中引入的 TPL。
    • 对于 CPU 密集型任务,请使用 .NET 4.0 中引入的 TPL。

    如果您没有 .NET 4.0,请使用线程池,除非您正在编写 ASP.NET 应用程序,在这种情况下您可能会求助于手动创建线程。

    一般来说,最好开始使用TPL 并将您的方法定位为任务,以便为引入 async/await 关键字的 .NET 4.5 做好准备。

    【讨论】:

    • @Darin :感谢您的回复。这里是 Windows 应用程序,我认为纯粹是 CPU 密集型任务,在产生 1000 个线程与 1000 个 del.begininvoke() 调用时性能如何
    • @MSK,在这种情况下肯定会使用 TPL,如果您使用的是旧版本的 .NET,请使用线程池(ThreadPool、BackgroundWorker、Async 委托,... => 它们都会结束无论如何都在线程池上)。在这种情况下不要手动生成线程。
    • @Darin:我不需要火而忘记。在这里,我需要一个专用线程来出列(不管线程池如何),同时它是一个长时间运行的进程。
    • 你说的是生产者/消费者模式吗?
    • 是的(它应用于队列的出队)