Пример асинхронной задачи c # - PullRequest
0 голосов
/ 22 сентября 2018

Я пытаюсь использовать асинхронную задачу и задачу для загрузки и обработки данных из хранилища.

Обычно я делаю эту задачу с двумя потоками с объединением, но я хочу попробовать эту языковую функциональность.

Код очень прост

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

Я бы обработал данные во время загрузки следующих данных.

Спасибо

Ответы [ 4 ]

0 голосов
/ 22 сентября 2018

То, что вы ищете, должно быть примерно таким

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");
}
0 голосов
/ 22 сентября 2018

Если вы не хотите блокировать при вызове ProcessData, вам нужно изменить его подпись на что-то вроде:

async Task ProcessData(byte[] data);

Затем вы можете вызывать ProcessData без блокировки, например:

await ProcessData(fileContent);

Имейте в виду, что для использования ключевого слова await вызывающая функция должна быть сама асинхронной.Также, вы можете прочитать много об асинхронной и ожидающей возможности здесь .

0 голосов
/ 22 сентября 2018

Вы можете сделать это с коллекцией производитель-потребитель в сочетании с задачей обработки.Общая идея шаблона «производитель-потребитель» состоит в том, что у вас есть производитель данных и один или несколько потребителей данных, которые дополнительно имеют разные скорости работы.

В вашем случае данные создаются каждые 3 с и потребляются каждые 5 с, поэтому выпросто нужна задача обработки / потребления - производство может быть выполнено другой задачей или может быть просто оставлено на усмотрение вашего основного потока - и подобный очереди набор, по которому обе стороны передают свою рабочую нагрузку и ожидают работы, не должен использовать ресурсы ЦП.

Для этого вы можете использовать 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;
0 голосов
/ 22 сентября 2018

Вы можете использовать метод Parallel.Foreach следующим образом:

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

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