Обработка асинхронных потоков - PullRequest
0 голосов
/ 31 мая 2019

Я (думаю, что я) понимаю различия между потоками и задачами.

  • Потоки позволяют нам делать несколько вещей параллельно (они связаны с процессором).
  • Асинхронныйзадачи высвобождают процессорное время, пока выполняются некоторые операции ввода-вывода (они связаны с вводом-выводом).

Теперь, скажем, я хочу выполнять несколько асинхронных задач параллельно.Например, я хочу загрузить несколько страниц постраничного ответа одновременно.Или я хочу записать новые данные в две разные базы данных.Как правильно обрабатывать потоки?Должны ли они быть асинхронными и ожидаемыми?Или асинхронная операция может быть только внутри потока?Как лучше всего обрабатывать ошибки?

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

public static Task<Thread> RunInThreadAsync<T>(T actionParam, Func<T, Task> asyncAction)
{
    var thread = new Thread(async () => await asyncAction(actionParam));
    thread.Start();
    return thread;
}

Это нормально?Или метод должен быть public static async Task<Thread>?Если да, что следует ожидать?Там нет thread.StartAsync().Или я должен использовать Task.Run вместо этого?

Примечание: Использование await Task.WhenAll или аналогичных подходов без явного нового потока не вариант для меня.Рабочий поток запускается в фоновом режиме (чтобы не блокировать основной поток), а затем обрабатывается другими службами в системе.

Ответы [ 2 ]

1 голос
/ 31 мая 2019

Я (думаю, что я) понимаю разницу между потоками и задачами.

Здесь отсутствует одна важная концепция: параллелизм. Параллелизм делает больше, чем одну вещь одновременно. Это отличается от «параллельного», который большинство разработчиков используют для обозначения «делать более чем одну вещь одновременно, используя потоки». Таким образом, параллелизм - это одна из форм параллелизма, а асинхронность - еще одна форма параллелизма.

Теперь, допустим, я хочу выполнять несколько асинхронных задач параллельно.

И вот проблема: смешивание двух форм параллелизма. Что вы действительно хотите сделать, так это несколько асинхронных задач одновременно . И способ сделать это через Task.WhenAll.

Использование await Task.WhenAll или аналогичные подходы без явного нового потока не вариант для меня. Рабочий поток выполняется в фоновом режиме (чтобы не блокировать основной поток), а затем обрабатывается другими службами в системе.

Этот аргумент не имеет никакого смысла. Асинхронный код не блокирует основной поток, потому что он асинхронный. Нет необходимости в явном обсуждении.

Если по какой-то неизвестной причине вам действительно нужен фоновый поток, просто поместите код в Task.Run. Thread следует использовать только для COM-взаимодействия; любое другое использование Thread является устаревшим кодом, как только он написан.

0 голосов
/ 31 мая 2019

System.Threading.Thread был в .NET с версии 1.1.Это позволяет вам контролировать несколько рабочих потоков в вашем приложении.Это использует только 1 ядро ​​вашего процессора.

В параллельной библиотеке задач (TPL) появилась возможность использовать несколько ядер на вашем компьютере с async Задачами или System.Threading.Tasks.Task<T>.

Мой подход к вашему сценарию «множественный загрузчик» заключается в создании нового CancellationTokenSource, который позволит мне отменить мои Задачи.Я бы начал создавать свои Task<T> и запускать их.Вы можете использовать Task.WaitAll(), чтобы сидеть и ждать.

Вы должны знать, что вы можете объединить свои задачи в последовательность, используя метод ContinueWith<T>().

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
async class Program
{
    static bool DownloadFile (string path)
    {
        // Do something here. long running task.

        // check for cancellation -> Task.Factory.CancellationToken.IsCancellationRequested

        return true;
    }
    static async void Main(string[] args)
    {
        var paths = new[] { "Somepaths", "to the files youwant", "to download" };
        List<Task<bool>> results = new List<Task<bool>>();
        var cts = new System.Threading.CancellationTokenSource();

        foreach(var path in paths)
        {
            var task = new Task<bool>(_path => DownloadFile((string)_path), path, cts.Token);
            task.Start();
            results.Add(task);
        }

        // use cts.Cancel(); to cancel all associated tasks. 

        // Task.WhenAll() to do something when they are all done. 
        // Task.WaitAll( results.ToArray() );  // to sit and wait. 

        Console.WriteLine("Press <Enter> to quit.");
        var final = Console.ReadLine();
    }
}

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...