记住 I/O 绑定任务,there is no thread。
您发布的段落并没有真正处理任务,例如:
var client = new TcpClient();
await client.ConnectAsync("example.com", 80);
var stream = client.GetStream();
// start reading from the socket
var rBuf = new byte[2048];
var tRecv = stream.ReadAsync(rBuf, 0, rBuf.Length);
// send data and wait for it to complete
var sBuf = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
await stream.WriteAsync(sBuf, 0, sBuf.Length);
// now await for the data
var bytesRecv = await tRecv;
Console.WriteLine($"Received {bytesRecv} bytes");
在处理底层流时,不会有两个同时线程同时做某事。
该段落所谈论的内容是这样的:
var client = new TcpClient();
await client.ConnectAsync("example.com", 80);
var stream = client.GetStream();
new Thread(() =>
{
var rBuf = new byte[2048];
var bytesRecv = stream.Read(rBuf, 0, rBuf.Length);
Console.WriteLine($"Received {bytesRecv} bytes");
}).Start();
Thread.Sleep(500); // ensure the above thread has started
new Thread(() =>
{
var sBuf = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
stream.Write(sBuf, 0, sBuf.Length);
}).Start();
Console.ReadKey(true);
在上面的示例中,您有两个不同的线程同时对底层流执行某些操作,并且没有“崩溃”。
至于你应该使用什么模式......你有几种可能性。您有上面的第一个任务示例(现代方法),或者您可以使用阻塞调用(“老派”方法)执行线程化的while(true) 方法。或者Begin... 和End... 方法(介于老式和现代之间)。
什么是最好的?你选。我个人喜欢在数据可用时触发事件,所以我倾向于使用BeginConnect/EndConnect、BeginReceive/EndReceive 等方法。
但有时,我喜欢使用ReadAsync() 执行while(true),但使用CancellationToken 来终止循环。
我确实不建议将while(true) 与阻塞调用一起使用。有了 TPL 为我们提供的出色工具,我们不必再启动通用线程来完成任何事情。