Многопоточность и асинхронность одновременно - PullRequest
0 голосов
/ 14 января 2019

У меня есть следующий код:

myObject object1 = null;
Thread obj1Thread = new Thread(() => { object1 = _myService.GetMethod(variable1, variable2); });
obj1Thread.Start();
obj1Thread.Join();


myObject object2 = null;
Thread obj2Thread = new Thread(() => { object2 = _myService.GetMethod2(variable3, variable4); });
obj2Thread.Start();
obj2Thread.Join();

Насколько я понимаю, этот код создаст 2 новых потока, запустит указанные методы, приостановит основной поток, пока оба эти потока не завершат, а затем продолжит выполнение.

Предполагая, что я говорю правильно, пока все хорошо.

Далее я хочу попробовать это:

myObject object1 = null;
Thread obj1Thread = new Thread(async () => { object1 = await _myService.GetMethod(variable1, variable2); });
obj1Thread.Start();
obj1Thread.Join();


myObject object2 = null;
Thread obj2Thread = new Thread(async () => { object2 = await _myService.GetMethod2(variable3, variable4); });
obj2Thread.Start();
obj2Thread.Join();

По сути, добавление асинхронного режима и ожидание в каждом потоке.

Компилятор принимает это изменение и, кажется, работает локально, но в порядке ли этот код, и может ли он вызвать какие-либо проблемы в дальнейшем, например, перепутаются ли потоки, не будут ждать, перепутать результаты и т.д.

У меня достаточно хорошее понимание асинхронности и базовое понимание многопоточности, и я не могу придумать ни одной причины, по которой это не сработает.

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

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Ваш код может быть параллельным и асинхронно ожидаемым в одной строке:

await Task.WhenAll(_myService.GetMethod(variable1, variable2), _myService.GetMethod2(variable3, variable4)). 

Это все, что тебе нужно. Нет тем. Нет присоединения. Если эти методы действительно являются вводом-выводом, потока не будет.

Как всегда, должны читать: https://blog.stephencleary.com/2013/11/there-is-no-thread.html

Если ваши методы возвращают разные результаты и их необходимо присвоить переменным, вы можете сделать это:

Task<int> task1 = _myService.GetMethod(variable1, variable2);
Task<string> task2 = _myService.GetMethod2(variable3, variable4);
// Both tasks started.

int a = await task1; // Wait for first task
string b = await task2; // If this already finished, it will just return the result
0 голосов
/ 31 января 2019

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

У меня достаточно хорошее понимание асинхронности и базовое понимание многопоточности, и я не могу придумать ни одной причины, по которой это не сработает.

Да, этот код вызовет у вас проблемы. Потоки не ждут, как вы ожидаете. Вы передаете async void лямбда в конструктор Thread, и этот поток выйдет , как только он достигнет await в этой лямбде, до того устанавливает переменную object1 / object2. Поэтому вполне возможно, что эти переменные останутся null после Join.

Правильное решение, как FCin отправлено , заключается в использовании асинхронного параллелизма. (Я избегаю здесь термина «параллельный», чтобы избежать путаницы с типом Parallel и библиотекой параллельных задач). Асинхронный параллелизм использует Task.WhenAll:

// Start both methods concurrently
var task1 = _myService.GetMethod(variable1, variable2);
var task2 = _myService.GetMethod2(variable3, variable4);

// (Asynchronously) wait for them both to complete.
await Task.WhenAll(task1, task2);

// Retrieve results.
myObject object1 = await task1;
myObject object2 = await task2;
0 голосов
/ 14 января 2019

Ваш приведенный выше код не использует многопоточность, он блокирует первый поток до его завершения, а затем запускает второй

obj1Thread.Join(); указывает вашему основному потоку дождаться выхода obj1Thread, прежде чем продолжить. Это означает, что он будет раскручивать obj1Thread, а затем ждать его завершения, что означает, что вы:

  1. создать тему 1
  2. Запустить поток 1
  3. Выходной поток 1
  4. создать тему 2
  5. Запустить поток 2
  6. Выходной поток 2

Вы хотите сделать:

myObject object1 = null;
Thread obj1Thread = new Thread(async () => { object1 = await _myService.GetMethod(variable1, variable2); });
obj1Thread.Start();
myObject object2 = null;
Thread obj2Thread = new Thread(async () => { object2 = await _myService.GetMethod2(variable3, variable4); });
obj2Thread.Start();
obj1Thread.Join();
obj2Thread.Join();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...