C# 如何通过Escape键正确取消并行异步IO任务?

C# 如何通过Escape键正确取消并行异步IO任务?,c#,async-await,task-parallel-library,.net-4.5,cancellation-token,C#,Async Await,Task Parallel Library,.net 4.5,Cancellation Token,我正在学习异步等待操作,并找到了一个解决方案 我考虑了本文的最后一个代码片段: public async Task ProcessWriteMult(CancellationToken cancellationToken) { string folder = @"tempfolder\"; List<Task> tasks = new List<Task>(); List<FileStream> sourceStreams = new List<File

我正在学习异步等待操作,并找到了一个解决方案

我考虑了本文的最后一个代码片段:

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();
    }
}
}
如何使用退出键正确取消

更新:

我插入了以下代码:

static void Main(string[] args)
{
    var cts=new CancellationTokenSource();
    ProcessWriteMult(cts);
    if(Console.ReadKey().Key == System.ConsoleKey.Escape)
        cts.Cancel();
}
但是,此代码不会取消方法
ProcessWriteMult(cts)

我做错了什么?

取消需要两种类型:一种是源,另一种是侦听器。即,您需要触发取消的
CancellationTokenSource
实例,您的代码应通过令牌侦听取消:

Task ProcessWriteMultAsync(CancellationTokenSource source)
{
  // ...
}

var cts = new CancellationTokenSource();
await ProcessWriteMultAsync(cts.Token);
if(Console.ReadKey().Key==System.ConsoleKey.Escape)
           cts.Cancell();

请不要使用
异步void
!它们只能用于事件处理程序。

取消需要两种类型:一种是源,另一种是侦听器。即,您需要触发取消的
CancellationTokenSource
实例,您的代码应通过令牌侦听取消:

Task ProcessWriteMultAsync(CancellationTokenSource source)
{
  // ...
}

var cts = new CancellationTokenSource();
await ProcessWriteMultAsync(cts.Token);
if(Console.ReadKey().Key==System.ConsoleKey.Escape)
           cts.Cancell();

请不要使用
异步void
!它们只能用于事件处理程序。

首先,不要使用
async void
。我不知道为什么MSDN示例会鼓励不好的做法,但还是不要这样做。使用
async void
意味着您的方法是“激发并忘记”,它不能异步等待,并且它内部发生的任何异常都将在线程池线程上抛出。相反,请使用
异步任务

现在,.NET 4.0引入了
CancellationTokenSource
的概念,它可以帮助您进行协作取消。这意味着您必须监视令牌,以便了解“外部”请求取消的人。这可以通过以下方式完成:

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);
}
试试看
{

对于(int index=1;index首先,不要使用
async void
。我不知道为什么MSDN示例会鼓励不好的做法,但还是不要这样做。使用
async void
意味着您的方法是“开火并忘记”,它不能异步等待,并且它内部发生的任何异常都将在线程池线程上引发。相反,请使用
async Task

现在,.NET 4.0引入了
CancellationTokenSource
的概念,它可以帮助您进行合作取消。这意味着您必须监视令牌,以便了解来自“外部”请求取消的人。这可以通过以下方式完成:

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);
}
试试看
{

对于(int index=1;index您研究过BackgroundWorker吗?它可能最适合您的场景,因为它支持开箱即用的取消,并在单独的线程上执行工作。另外请参见:您研究过BackgroundWorker吗?它可能最适合您的场景,因为它支持开箱即用的取消并在单独的线程上执行工作。另请参见:
控制台。如果OP愿意用Esc替换Ctrl-C,则CancelKeyPress
事件可能是轮询的更好选择。否则+1:)@今天的鼻比率操作被破坏了。这一切都是关于Esc;
控制台。如果OP愿意用Esc换成Ctrl-C,取消按键
事件可能是轮询的更好选择。否则+1:)@今天的鼻比率操作被破坏了。这都是关于Esc;p