Создаю и запускаю задачу вот так:
var task = new Task(WorkWithResult, cts.Token); //cts.Token - маркер отмены, но это не важно
task.Start();
Переменные, которые используются в WorkWithResult:
var result = new int[N];
string stringResult = string.Empty;
Жду завершения задачи стандартно, вот так:
await task.ConfigureAwait(true);
WorkWithResult - локальная функция, выглядит вот так:
void WorkWithResult()
{
var sbResult = new StringBuilder(N * 5);
var progressValue = 0.0;
var progressStep = 100d / N / 2;
result[0] = PrimeNumbers.Next_prime(0);
progress.Report((int) (progressValue += progressStep));
for (var i = 0; i < result.Length - 1; i++)
{
result[i + 1] = PrimeNumbers.Next_prime(result[i]);
cts.Token
.ThrowIfCancellationRequested();
progress.Report((int) (progressValue += progressStep));
}
foreach (var number in result)
{ // Блокировка UI. Почему?
sbResult.AppendLine(number.ToString());
cts.Token
.ThrowIfCancellationRequested();
progress.Report((int) (progressValue += progressStep));
}
stringResult = sbResult.ToString();
}
Во время выполнения последнего цикла происходит блокировка UI(массив чисел из 100 000, блокировка на 1 секунду). Почему? Код явно выполняется в другом потоке, я же запускаю его через Task
. Все, чем отличается этот цикл от цикла 1 - это sbResult.AppendLine
.
Я подумал, что, возможно, дело в обращениях к массиву result
, который создан не в том потоке, что выполняется WorkWithResult
, но ведь блокировки не происходит в цикле 1.
Почему происходит блокировка, как ее избежать?
В первом цикле вы отправляете отчеты с некоторой задержкой между ними (задержка обусловлена сложностью поиска простого числа). Вот в этот промежуток UI и успевает прорисоваться, отреагировать на действия пользователя и т.п.
Во втором цикле вы молотите новые репорты без остановки, ведь AppendLine
работает очень быстро! (Даже быстрее чем отправка отчета) А потому поток UI занят исключительно обработкой отчетов и не успевает сделать ничего кроме обработки отчетов.
Из возможных исправлений самый простой способ - это убрать progress.Report
из второго цикла.
Альтернативный вариант - отправлять каждый (N/50)й отчет, а остальные пропускать (если нужна точность до десятых долей процента - то каждый (N/500)й).
Еще один вариант - отслеживать время работы и отправлять отчет каждые полсекунды.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
При попадании по игроку нужно обновлять показания его здоровья на его сторонеПочему этого не происходит и как правильно это реализовать?
В общем, хочу что бы перед добавление записи в коллекцию у меня выполнялось некоторое действие