示例异步任务C#

时间:2018-09-22 11:44:28

标签: c# asynchronous task

我正在尝试使用异步和任务从存储中加载和处理数据。

我通常使用带有连接的两个线程来执行此任务,但是我想尝试这种语言功能。

代码很简单

Foreach(var file in files)
{
    var data = LoadFromFile(file); // require 3sec
    ProcessData(data); // require 5 sec
}

我将在加载下一个数据时处理数据。

谢谢

4 个答案:

答案 0 :(得分:1)

您可以结合生产者-消费者集合和处理任务来执行此操作。生产者-消费者模式的总体思想是,您有一个数据生产者和一个或多个数据消费者,而且它们具有不同的运行速度。

在您的情况下,数据每3秒钟产生一次,每5秒钟消耗一次,因此您只需要一个处理/消耗任务-生产可以由另一个任务完成,也可以只留给您的主线程-并且像队列一样收集既可以传达工作量又可以等待工作的资源,则不应使用CPU资源。

为此,您可以使用BlockingCollection,其详细信息在https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/blockingcollection-overview中进行了描述。

针对您的案例的示例实现为:

var work = new BlockingCollection<Data>();

// instantiate processing task
var processingTask = Task.Run(() =>
{
  foreach (var data in work.GetConsumingEnumerable())
  {
    ProcessData(data);
  }
});

// produce data for processing
for (int i = 0; i < 10; i++)
{
    var data = LoadFromFile(file);
    work.Add(data); // processing will start as soon as data is added
}
// mark that no more data will come, so the processing knows it doesn't need to wait for more work
work.CompleteAdding();

// await end of processing
await processingTask;

答案 1 :(得分:0)

如果不想在调用ProcessData时阻塞,则需要将其签名更改为:

async Task ProcessData(byte[] data);

然后,您可以像这样不阻塞地调用ProcessData:

await ProcessData(fileContent);

请注意,为了使用await关键字,调用函数本身应该是异步的。此外,您还可以阅读有关异步和等待功能here的很多文章。

答案 2 :(得分:0)

您要寻找的应该是这样的

static void Main()
{
    List<string> files = new List<string>() { "file1", "file2" };
    foreach (var file in files)
    {
        Work(file);
    }
    Console.ReadLine();
}

private static async void Work(string file)
{
    var data = await LoadFromFile(file);
    await ProcessData(data);
}

private static async Task ProcessData(string data)
{
    await Task.Delay(5000);
    Console.WriteLine($"Processed {data}");
}

private static async Task<string> LoadFromFile(string file)
{
    await Task.Delay(3000);
    Console.WriteLine($"Loaded {file}");
    return file.Replace("file", "data");
}

但是,我相信您真正需要的是Parallel.ForEach

static void Main()
{
    List<string> files = new List<string>() { "file1", "file2" };
    Parallel.ForEach(files, (file) =>
    {
        var data = LoadFromFile(file);
        ProcessData(data);
    });
    Console.ReadLine();
}

private static void ProcessData(string data)
{
    Thread.Sleep(3000);
    Console.WriteLine($"Processed {data}");
}

private static string LoadFromFile(string file)
{
    Thread.Sleep(5000);
    Console.WriteLine($"Loaded {file}");
    return file.Replace("file", "data");
}

答案 3 :(得分:-1)

您可以像这样使用Parallel.Foreach方法:

        foreach(var file in files)
        {
            var data = LoadFromFile(file);

            new TaskFactory().StartNew(() => { ProcessData(data); });
        }