有一个Tcp客户端类,我的想法很简单:连接服务器,异步启动监听服务器消息的方法。当我运行 ReadStream 方法时,我特别不指定 await 以免等待它完成,但是,仍然没有发生异步。
class Client : IDisposable
{
...
public async Task ConnectAsync(string host, int port)
{
await tcpClient.ConnectAsync(IPAddress.Parse(host), port);
if (tcpClient.Connected)
{
System.Console.WriteLine("Connected!");
var task = ReadStream(token);
activeTasks.Add(task);
System.Console.WriteLine("Task runned");
}
else
{
System.Console.WriteLine("Failed to connect :(");
}
}
...
private async Task<string> ReadStringFromStreamAsync(NetworkStream stream, int size)
{
var buffer = new byte[size];
int length = await stream.ReadAsync(buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer, 0, length);
}
private async Task ReadStream(CancellationToken token)
{
var stream = tcpClient.GetStream();
while (!token.IsCancellationRequested)
{
if (stream.DataAvailable)
{
string message = await ReadStringFromStreamAsync(stream, 1024);
System.Console.WriteLine("Recieved message: " + message);
}
}
}
}
如果我通过 运行该方法Task.Run(()=>ReadStream(token))
,那么一切都会按我的需要进行。这对我来说有点奇怪,因为我的方法也会返回Task
,并且根据我的逻辑(很可能是不正确的),当遇到意外时,Task
该方法应该异步运行。在所有的培训时间里,我已经对这个话题进行了 3 次深入研究,但仍然对这种机制的功能的想法非常薄弱。因此,如果在解决此问题的示例中某些部分能达到我的要求,那就太好了。因此,我有两个问题:
为什么
ReadStream
尽管存在该方法但没有异步启动该方法await
(通常没有说明由于它不存在该方法是同步执行的)?如果通过 异步运行这个操作仍然是正确的
Task.Run
,那么我对应该将哪个任务放在活动任务列表中有点困惑:var task = Task.Run(()=>ReadStream(token)); activeTasks.Add(task);
或者
Task.Run(()=>{var task = ReadStream(token); activeTasks.Add(task);});
看。关键字本身
async
并不能保证该方法是异步的。它只会创造条件,在这些条件下您可以自己轻松地在方法中实现异步。*async
-methods 的一个特点是该方法在第一个await
. 在您的情况下,循环同步旋转,while (!token.IsCancellationRequested)
直到stream.DataAvailable
它变为 equaltrue
,即直到数据到达!在此之前,控制不会返回到调用方法。应该做什么?您需要使等待数据异步。最有可能的是,只有以下代码可以工作:
(但我不能保证,因为您没有提供方法代码
ReadStringFromStreamAsync
)。如果您的代码只是从流中读取一行,那么您可以使用
StreamReader
:*怎么做?您希望您的方法代码快速运行,而不是像 那样有空闲的同步等待循环
while (!condition) { /* do nothing */ }
,并且所有需要等待缓慢结果的地方(例如,从网络或磁盘读取数据)都是异步的。如果你需要暂停,它不应该在之后Thread.Sleep()
,而是在之后await Task.Delay()
。而且您不应该在内部调用同步慢速函数,而应使用快速或异步函数。