c# - 在 C# 控制台应用程序中使用 async 和 await 异步处理文件列表

标签 c# multithreading asynchronous async-await

我在一个简单的小型控制台应用程序中使用 C# 中的 asyncawait 进行游戏。我的目标很简单:以异步方式处理一系列文件,这样一个文件的处理就不会阻塞其他文件的处理。没有一个文件相互依赖,并且有(比方说)数千个文件要处理。

这是我目前的代码。

public class MyClass
{
    public void Go()
    {
        string[] fileSystemEntries = Directory.GetFileSystemEntries(@"Path\To\Files");

        Console.WriteLine("Starting to read from files!");
        foreach (var filePath in fileSystemEntries.OrderBy(s => s))
        {
            Task task = new Task(() => DoStuff(filePath));
            task.Start();
            task.Wait();
        }
    }

    private async void DoStuff(string filePath)
    {
        await Task.Run(() =>
        {
            Thread.Sleep(1000);
            string fileName = Path.GetFileName(filePath);
            string firstLineOfFile = File.ReadLines(filePath).First();
            Console.WriteLine("{0}: {1}", fileName, firstLineOfFile);
        });
    }
}

我的 Main() 方法只是调用这个类:

public static class Program
{
    public static void Main()
    {
        var myClass = new MyClass();
        myClass.Go();
    }
}

不过,我似乎遗漏了这个异步编程模式的一些部分,因为每当我运行该程序时,实际处理了多少文件似乎是随机的,从一个都没有到全部六个(在我的示例文件集)。

基本上,主线程不会等待所有文件都被处理,我想这是异步运行的一部分,但我不太想要那样。我想要的只是:在尽可能多的线程中处理尽可能多的这些文件,但在完成之前仍然等待它们全部完成处理。

最佳答案

async/await 背后的主要设计目标之一是促进自然异步 I/O API 的使用。有鉴于此,您的代码可能会像这样重写(未经测试):

public class MyClass
{
    private int filesRead = 0;

    public void Go()
    {
        GoAsync().Wait();
    }

    private async Task GoAsync()
    {
        string[] fileSystemEntries = Directory.GetFileSystemEntries(@"Path\To\Files");

        Console.WriteLine("Starting to read from files! Count: {0}", fileSystemEntries.Length);

        var tasks = fileSystemEntries.OrderBy(s => s).Select(
            fileName => DoStuffAsync(fileName));
        await Task.WhenAll(tasks.ToArray());

        Console.WriteLine("Finish! Read {0} file(s).", filesRead);
    }

    private async Task DoStuffAsync(string filePath)
    {
        string fileName = Path.GetFileName(filePath);
        using (var reader = new StreamReader(filePath))
        {
            string firstLineOfFile = 
                await reader.ReadLineAsync().ConfigureAwait(false);
            Console.WriteLine("[{0}] {1}: {2}", Thread.CurrentThread.ManagedThreadId, fileName, firstLineOfFile);
            Interlocked.Increment(ref filesRead);
        }
    }
}

请注意,它不会显式生成任何新线程,但这可能会在 await reader.ReadLineAsync().ConfigureAwait(false) 的幕后发生。

关于c# - 在 C# 控制台应用程序中使用 async 和 await 异步处理文件列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23444860/

相关文章:

c# - 多列分组

c# - 向 XAML 中的元素添加自定义属性?

java - 为什么足够的同步边集是唯一的以及如何构建它?

python - Python:在图像上绘制两个区域

java - 如何获取当前正在运行的线程

python - 在 python 中等待之前,不会在异步函数中调用打印函数

c# - Windows Phone 8.1 运行时 HttpClient 异步,结果相同

c# - 如何防止创建迁移并将它们应用于 Entity Framework Core 6 中的指定 dbContext?

python - Python 中的自定义协程

ios - Swift 将 PHAsset 数组转换为 URL 数组