如何通过Escape键正确取消并行异步IO任务?
How to properly cancel parallel asynchronous IO Task by Escape key?
我正在学习异步等待操作并找到了 very useful article。
我考虑这篇文章的最后一个代码片段:
public async Task ProcessWriteMult(CancellationToken cancellationToken)
{
string folder = @"tempfolder\";
List<Task> tasks = new List<Task>();
List<FileStream> sourceStreams = new List<FileStream>();
try
{
for (int index = 1; index <= 10; index++)
{
string text = "In file " + index.ToString() + "\r\n";
string fileName = "thefile" + index.ToString("00") + ".txt";
string filePath = folder + fileName;
byte[] encodedText = Encoding.Unicode.GetBytes(text);
FileStream sourceStream = new FileStream(filePath,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
sourceStreams.Add(sourceStream);
tasks.Add(theTask);
}
await Task.WhenAll(tasks);
}
finally
{
foreach (FileStream sourceStream in sourceStreams)
{
sourceStream.Close();
}
}
}
我已经尝试了一些代码来取消任务,但是,恕我直言,这些都是非常丑陋的尝试。在这次尝试中,我的程序流程等待用户按下按键,但我希望这段代码能够工作,直到用户按下 Esc 按钮,如事件:
if(Console.ReadKey().Key==System.ConsoleKey.Escape)
cts.Cancel();
如何正确使用退出键取消?
更新:
我已插入此代码:
static void Main(string[] args)
{
var cts=new CancellationTokenSource();
ProcessWriteMult(cts);
if(Console.ReadKey().Key == System.ConsoleKey.Escape)
cts.Cancel();
}
但是,此代码不会取消方法 ProcessWriteMult(cts)
。
我做错了什么?
取消需要两种类型:一种是源,另一种是监听器。 IE。你需要一个 CancellationTokenSource
的实例来触发取消,你的代码应该通过令牌监听取消:
Task ProcessWriteMultAsync(CancellationTokenSource source)
{
// ...
}
var cts = new CancellationTokenSource();
await ProcessWriteMultAsync(cts.Token);
if(Console.ReadKey().Key==System.ConsoleKey.Escape)
cts.Cancell();
请不要使用 async void
!它们应该只用于事件处理程序。
首先,不要使用 async void
。我不确定为什么 MSDN 示例会鼓励不良做法,但仍然不要那样做。使用 async void
意味着你的方法是 "fire and forget",它不能被异步等待,并且它内部发生的任何异常都将在线程池线程上抛出。相反,使用 async Task
.
现在,.NET 4.0 引入了CancellationTokenSource
的概念,它可以帮助您合作取消。这意味着您必须监控令牌才能知道 "the outside" 中有人请求取消。这可以按如下方式完成:
try
{
for (int index = 1; index <= 10; index++)
{
// Monitor the token, you decide where.
cancellationToken.ThrowIfCancellationRequested();
string text = "In file " + index.ToString() + "\r\n";
string fileName = "thefile" + index.ToString("00") + ".txt";
string filePath = folder + fileName;
byte[] encodedText = Encoding.Unicode.GetBytes(text);
FileStream sourceStream = new FileStream(filePath,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
sourceStreams.Add(sourceStream);
tasks.Add(theTask);
}
await Task.WhenAll(tasks);
}
However, this code does not cancel method ProcessWriteMult(cts). What
am I doing wrong?
可能是当你按下escape时,方法已经执行完毕。您可以通过在特定时间间隔(比如 5 秒)等待 Task.Delay
来测试这一点,然后才监控取消令牌。
我正在学习异步等待操作并找到了 very useful article。
我考虑这篇文章的最后一个代码片段:
public async Task ProcessWriteMult(CancellationToken cancellationToken)
{
string folder = @"tempfolder\";
List<Task> tasks = new List<Task>();
List<FileStream> sourceStreams = new List<FileStream>();
try
{
for (int index = 1; index <= 10; index++)
{
string text = "In file " + index.ToString() + "\r\n";
string fileName = "thefile" + index.ToString("00") + ".txt";
string filePath = folder + fileName;
byte[] encodedText = Encoding.Unicode.GetBytes(text);
FileStream sourceStream = new FileStream(filePath,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
sourceStreams.Add(sourceStream);
tasks.Add(theTask);
}
await Task.WhenAll(tasks);
}
finally
{
foreach (FileStream sourceStream in sourceStreams)
{
sourceStream.Close();
}
}
}
我已经尝试了一些代码来取消任务,但是,恕我直言,这些都是非常丑陋的尝试。在这次尝试中,我的程序流程等待用户按下按键,但我希望这段代码能够工作,直到用户按下 Esc 按钮,如事件:
if(Console.ReadKey().Key==System.ConsoleKey.Escape)
cts.Cancel();
如何正确使用退出键取消?
更新:
我已插入此代码:
static void Main(string[] args)
{
var cts=new CancellationTokenSource();
ProcessWriteMult(cts);
if(Console.ReadKey().Key == System.ConsoleKey.Escape)
cts.Cancel();
}
但是,此代码不会取消方法 ProcessWriteMult(cts)
。
我做错了什么?
取消需要两种类型:一种是源,另一种是监听器。 IE。你需要一个 CancellationTokenSource
的实例来触发取消,你的代码应该通过令牌监听取消:
Task ProcessWriteMultAsync(CancellationTokenSource source)
{
// ...
}
var cts = new CancellationTokenSource();
await ProcessWriteMultAsync(cts.Token);
if(Console.ReadKey().Key==System.ConsoleKey.Escape)
cts.Cancell();
请不要使用 async void
!它们应该只用于事件处理程序。
首先,不要使用 async void
。我不确定为什么 MSDN 示例会鼓励不良做法,但仍然不要那样做。使用 async void
意味着你的方法是 "fire and forget",它不能被异步等待,并且它内部发生的任何异常都将在线程池线程上抛出。相反,使用 async Task
.
现在,.NET 4.0 引入了CancellationTokenSource
的概念,它可以帮助您合作取消。这意味着您必须监控令牌才能知道 "the outside" 中有人请求取消。这可以按如下方式完成:
try
{
for (int index = 1; index <= 10; index++)
{
// Monitor the token, you decide where.
cancellationToken.ThrowIfCancellationRequested();
string text = "In file " + index.ToString() + "\r\n";
string fileName = "thefile" + index.ToString("00") + ".txt";
string filePath = folder + fileName;
byte[] encodedText = Encoding.Unicode.GetBytes(text);
FileStream sourceStream = new FileStream(filePath,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
sourceStreams.Add(sourceStream);
tasks.Add(theTask);
}
await Task.WhenAll(tasks);
}
However, this code does not cancel method ProcessWriteMult(cts). What am I doing wrong?
可能是当你按下escape时,方法已经执行完毕。您可以通过在特定时间间隔(比如 5 秒)等待 Task.Delay
来测试这一点,然后才监控取消令牌。