Можно ли изменить второй и получить результат, аналогичный первому примеру?
Когда вы передаете переменную или объект в Task.Run(()=> DoSomething(index))
, вы захватываете переменную.
В некотором смысле вы не просто отправляете эту переменную как значение или объект, но предоставляете этому потоку прямой доступ к исходной переменной. (Это очень обобщенно и имеет много нюансов).
Проблема, с которой вы, скорее всего, столкнетесь, заключается в том, что CLR пытается захватить index
, который является итератором, область действия которого не может выйти за его границы, если только какая-либо попытка сделать это не останется в стеке (в основном тот же поток , опять же над обобщением).
Когда CLR «захватывает» index
, она захватывает только случайное значение, которое было index
(из-за условий гонки), или последнее значение, которое было index
, что двойное un -интуитивный, потому что вы явно сказали ему, что index
никогда не должно переходить к 9
в этой строке здесь for (var index = 0; index < 9; index++)
.
Вот хитрая вещь: когда CLR фиксирует index
, она фиксирует любое последнее значение для index
. Но после завершения цикла index
увеличивается еще раз, в результате чего 9
становится последним значением index
.
Это может привести к целому ряду проблем, особенно если вы работаете с массивами, IndexOutOfBoundsException
!
Как это исправить
На самом деле исправить очень просто! Просто создайте временную переменную в цикле и передайте ее вместо index
напрямую.
Вот пример:
void Main()
{
var tasks = new List<Task<int>>();
for (var index = 0; index < 9; index++)
{
int tmpIndex = index;
var task = Task.Run(() => DoSomething(tmpIndex ));
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
Можно ли изменить второй и получить результат, аналогичный первому примеру?
Дополнительное примечание
никогда не полагайтесь на то, что данные из задач будут в порядке, если вы явно не реализовали гарантию того, что элементы возвращаются в порядке. TaskScheduler
выбирает Tasks
для работы в обычном режиме FIFO (первым поступил, первым обслужен), однако, если TaskScheduler
оптимизирует, расставляет приоритеты или сдвигает задачи (что происходит часто), ваши задачи не будут выполняться. выполнить по порядку, и впоследствии результаты, которые вы получите, не будут упорядочены.
person
DekuDesu
schedule
28.05.2021