如果您没有输入任何输入,为什么以下代码没有完成?为什么即使取消令牌取消后它仍然会响应按键?
// Set up a cancellation token
var cancellationSource = new CancellationTokenSource();
// Cancel the cancellation token after a little bit of time
Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(2));
cancellationSource.Cancel();
Console.WriteLine("Canceled the cancellation token");
});
// Wait for user input, or the cancellation token
Task.Run(async () =>
{
try
{
using (var input = Console.OpenStandardInput())
{
var buffer = new byte[1];
Console.WriteLine("Waiting for input");
await input.ReadAsync(buffer, 0, 1, cancellationSource.Token); // This is impossible to cancel???
Console.WriteLine("Done waiting for input"); // This never happens until you press a key, regardless of the cancellation token
}
}
catch (Exception e)
{
Console.WriteLine(e.Message); // No errors
}
})
.Wait(); // Block until complete
The documentation for Stream.ReadAsync says:
如果操作在完成之前取消,则返回的任务包含Status属性的Canceled值。
这意味着取消取消令牌将取消操作,对吧?但出于某种原因the source code for Stream.ReadAsync如果事先没有取消,则{@ 3}}对取消令牌不做任何事情:
public virtual Task<int> ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
// If cancellation was requested, bail early with an already completed task.
// Otherwise, return a task that represents the Begin/End methods.
return cancellationToken.IsCancellationRequested
? Task.FromCancellation<int>(cancellationToken)
: BeginEndReadAsync(buffer, offset, count);
}
因此,取消令牌参数毫无意义 - 如何取消该异步读取?
答案 0 :(得分:0)
在Console输入的特定情况下,似乎没有其他方法可以轮询Console.KeyAvailable属性:
var buffer = new byte[1];
Console.WriteLine("Waiting for input");
while (!Console.KeyAvailable && !cancellationSource.Token.IsCancellationRequested)
await Task.Delay(10); // You can add the cancellation token as a second parameter here, but then canceling it will cause .Delay to throw an exception
if (cancellationSource.Token.IsCancellationRequested)
{
Console.WriteLine("Canceled; no longer waiting for input");
}
else
{
await input.ReadAsync(buffer, 0, 1);
Console.WriteLine("Got user input");
}
对我而言,这表明您无法以一般方式可靠地使用Stream.ReadAsync
,因为您必须根据您正在处理的Stream实现做不同的事情。
编辑:
考虑到这一点,有意义的是你无法取消ReadAsync
,因为Stream
抽象类没有任何处理异步操作的抽象方法;实现Stream
所必须做的就是实现一些getter和一些阻塞方法,这是Microsoft在__ConsoleStream
类中所做的全部。
由于可以保证存在于Stream上的唯一方法是阻塞方法,并且因为无法取消阻塞调用(您甚至无法在另一个线程上执行阻塞IO操作,因此取消该线程,并且操作停止),不可能有可取消的异步操作。
因此,Microsoft应该已经删除了取消令牌参数,或者应该将抽象的异步可取消方法放入Stream
类中,以便使__ConsoleStream
的人员被迫实施它们。 / p>
答案 1 :(得分:0)
马特,我有同样的问题。如果您使用
,我找不到取消它的方法Port.BaseStream.ReadAsync()
如果无法读取所需的字节数,那么我发现能够使用
再次读取端口的唯一方法Port.BaseStream.ReadAsync()
此事件后要致电
Port.DiscardInBuffer()
在Port.BaseStream.ReadAsync()
之后
无法读取所需的字节数。然后,您可以再次写入端口以请求要再次读取的数据并使用
正确读取Port.Basestream.ReadAsync()
再次假定可以读取正确的字节数。我成功地使用它实现了Retry函数。另一种可行的方法是通过检查
来检查是否有可读取的字节 Port.BytesToRead = 0
如果是这样,则不要呼叫
Port.BaseStream.ReadAsync()