Long Running Blocking Methods. Difference between Blocking, Sleeping, Begin/End and Async

蓝咒 提交于 2020-01-13 05:06:31

问题


This question is not about designs or patterns and which to use. The heart of this question is about what is happening regarding threads and blocking.

This example is to apply to any blocking method that is designed to perform the same action continuously. In this case it is a blocking read or write on a networkstream. Is there any appreciable difference behind the scenes as to threading and performance between the methods?

My assumption is that each of the methods below creates a thread or uses a pooled thread. Then blocks that thread until there is data to be read. Having said that and in that context, Is there any appreciable difference as to threading, performance and scalability between the methods?

Currently I am creating a server application. This application will have 1000 clients creating tcp connections. These connections will remain open, sending and receiving small amounts of data often. I am looking to use model A since it is the easiest to implement and the most maintainable. Will I end up with 1000 threads no matter which pattern is chosen?

Please note that these methods are just to give an idea of the structure and not something that would be used without proper streaming reads, timeouts, and exception handling.

Method A: Blocking

Task.Factory.StartNew(ReadMessage,TaskCreationOptions.LongRunning);
private void ReadMessage()
{
   while(true)
   {
      TcpClient.Read();
   }
}

Method B: Sleeping

Task.Factory.StartNew(ReadMessage,TaskCreationOptions.LongRunning);
private void ReadMessage()
{
    while(true)
    {
        if(TcpClient.DataAvailable)
            TcpClient.Read();
        else
            Thread.Sleep(1);
    }
}

Method C: Recursive Begin/End

private void ReadMessage()
{
      stream.BeginRead(readCallBack)
}
private void readCallBack()
{
      stream.EndRead();
      stream.BeginRead(readCallBack)
}

Method D: Async from BCL socket.ReceiveAsync()

private void readCallBack()
{
    while(true)
    {
        await socket.ReceiveAsync(eventArgs);
    }
}

Method E: Async method with blocking Read (Uses method D to call but is a custom method instead of using the built in exstendion of sockets from the BCL)

private async Task<byte[]> ReceiveAsync()
{
   return await Task.Factory.StartNew(() => TcpClient.Read());
}

回答1:


My assumption is that each of the methods below creates a thread or uses a pooled thread. Then blocks that thread until there is data to be read.

Not at all. Your first two examples block threads, but your second two examples are asynchronous.

Asynchronous methods work by queueing the work to the OS and then waiting for a callback, in this case on an I/O completion port. So while the read is pending, there are no threads being used.

Since asynchronous approaches don't use as many threads, they scale better.

Your last example (async) is really just as simple as your first example, and that would be the approach I recommend unless you use Rx or TPL Dataflow. When doing socket communications, by the time you consider error handling such as detection of dropped connections, asynchronous communication is clearly the way to go.



来源:https://stackoverflow.com/questions/15059674/long-running-blocking-methods-difference-between-blocking-sleeping-begin-end

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!