заполнить 2 списка, используя параллелизм - PullRequest
2 голосов
/ 11 февраля 2020

У меня есть 2 длительных метода, которые получают данные из внешних источников и возвращают результаты в виде списков:

public static class Helper1
{
    public static List<X> GetStuff()
    {
        // some long running stuff
    }
}

public static class Helper2
{
    public static List<Y> GetStuff()
    {
        // some long running stuff
    }
}

Я хотел бы запускать их параллельно, а не последовательно. Моя первая попытка:

var task1 = new Task> (() => Helper1.GetStuff ()); var task2 = new Task> (() => Helper2.GetStuff ());

var whenAllTask = Task.WhenAll(task1, task2);

task1.Start();
task2.Start();

Кажется, ничего не происходит, и мне интересно, как я могу получить доступ к содержимому списков впоследствии (программа продолжается последовательно). Спасибо!

PS:

Сейчас я использую следующий код, учитывая ответ Робина Б.:

 var task1 = new Task<List<X>>(() => Helper1.GetStuff(), TaskCreationOptions.LongRunning);
    var task2 = new Task<List<Y>>(() => Helper1.GetStuff(), TaskCreationOptions.LongRunning);

    var whenAllTask = Task.WhenAll(task1, task2).Wait();

    List<X> lst1 = task1.Result;
    List<Y> lst2 = task2.Result;

К сожалению, ничего не происходит, похоже, застрял.

PPS:

Мне кажется, это работает:

var task1 = Task.Factory.StartNew<List<X>>(() => Helper1.GetStuff(), TaskCreationOptions.LongRunning));
var task2 = Task.Factory.StartNew<List<Y>>(() => Helper2.GetStuff(), TaskCreationOptions.LongRunning);

var allTasks = new Task[] { task1, task2 };

Task.WaitAll(allTasks);

List<X> lst1 = task1.Result;
List<Y> lst2 = task2.Result;

Ответы [ 3 ]

3 голосов
/ 11 февраля 2020

WhenAll будет ожидать всех заданных запущенных задач. Таким образом, вам придется начать их в первую очередь. Также Если вы используете Task<T>, вы можете получить результат Задания после его завершения, прочитав свойство Task<T>.Result.

Вы также заметите, что Task.WhenAll вернет ожидаемое. Поэтому вам придется позвонить туда Wait(), иначе вы просто выстрелите и забудете.

Вот пример:

  class Program
  {
    static void Main()
    {
      Task<List<int>> t1 = new Task<List<int>>(GetList);
      Task<List<int>> t2 = new Task<List<int>>(GetList);

      t1.Start();
      t2.Start();

      Task.WhenAll(t1, t2).Wait();

      Console.WriteLine("Both should have ended now");

      List<int> lst1 = t1.Result;
      List<int> lst2 = t2.Result;

      Console.ReadKey(true);
    }

    public static List<int> GetList()
    {
      Console.WriteLine("Started");

      Random rng = new Random();

      List<int> lst = new List<int>();

      for(int i = 0; i < 1000000; i++)
      {
        lst.Add(rng.Next());
      }

      Console.WriteLine("Ended");

      return lst;
    }
  }

РЕДАКТИРОВАТЬ Возможно, вы захотите прочитать на await против Wait(). Я имел в виду, что вы говорите, что программа продолжается последовательно, что вы находитесь в чисто синхронном контексте и вам просто нужно улучшить производительность извлечения. Но если вы вызываете этот код из потока пользовательского интерфейса или аналогичного, будьте осторожны, так как вызов Wait() заблокирует ваш поток пользовательского интерфейса. В этом случае использование await будет лучшим вариантом. ( ожидание против Task.Wait - тупик? )

1 голос
/ 11 февраля 2020

Более чистый способ - сделать ваши методы асинхронными, чтобы их можно было вызывать асинхронно. Вы можете определить свои методы как асинхронные, используя ключевое слово async:

public static class Helper1
{
    public static async Task<List<string>> GetStuff()
    {
        return await Task.Run(() => new List<string>{"78", "98", "56",});
    }
}

public static class Helper2
{
    public static async Task<List<int>> GetStuff()
    {
        return await Task.Run(() => new List<int>{1, 2, 3, 4, 5, 6});
    }
}

Затем вызывайте их следующим образом. Ключевым моментом здесь является ключевое слово await, которое сообщает компилятору, что задачи должны быть выполнены на этом этапе.

static async Task Main(string[] args)
{
    var task1 = Helper1.GetStuff();
    var task2 = Helper2.GetStuff();

    await Task.WhenAll(task1, task2);

    Console.WriteLine(task1.Result);
    Console.WriteLine(task2.Result);
}
0 голосов
/ 12 февраля 2020

Мне кажется, это работает:

var task1 = Task.Factory.StartNew<List<X>>(() => Helper1.GetStuff(), TaskCreationOptions.LongRunning));
var task2 = Task.Factory.StartNew<List<Y>>(() => Helper2.GetStuff(), TaskCreationOptions.LongRunning);

var allTasks = new Task[] { task1, task2 };

Task.WaitAll(allTasks);

List<X> lst1 = task1.Result;
List<Y> lst2 = task2.Result;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...