Поддержка отчетов о ходе выполнения и дополнительных результатов в .NET 4.0 "Параллельная библиотека задач"
Я знаю, что Task Parallel Library все еще находится в бета-версии, и, вероятно, будет меньше ресурсов, но из того, что я прочитал, библиотеки дает особое отношение к расписание задач, обработка исключений и отмена.
Но я не нахожу ссылки на отчет о проделанной работе и отправку инкрементных результатов из задач. Эти две вещи кажутся слишком важными для игнорирования. Можете ли вы рассказать о том, как обращаться с ними в параллельной библиотеке задач или ссылаться на некоторые статьи, которые их объясняют?
Ответы
Ответ 1
В этом примере обновляется индикатор выполнения:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
class SimpleProgressBar : Form
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.Run(new SimpleProgressBar());
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
int iterations = 100;
ProgressBar pb = new ProgressBar();
pb.Maximum = iterations;
pb.Dock = DockStyle.Fill;
Controls.Add(pb);
Task.ContinueWith(delegate
{
Parallel.For(0, iterations, i =>
{
Thread.SpinWait(50000000); // do work here
BeginInvoke((Action)delegate { pb.Value++; });
});
});
}
}
Обновление индикатора выполнения из Parallel.For
Ответ 2
Это один из моих лучших результатов поиска и пока нет примера для прогресса в Task Parallel Library
прямо здесь...
Сегодня я просто столкнулся с TPL, потому что хочу разработать новое многопоточное приложение, но без использования BackgroundWorker
(потому что раньше я где-то читал о задаче с хорошим кодом)
Я компилирую пример из ответа @Stephen Cleary, его связь довольно сложна для поиска прогресса и некоторых других веб-сайтов.
Это очень простой пример того, как сделать Прогресс и Завершено с помощью безопасного потока пользовательского интерфейса:
TaskScheduler currentTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task<string>.Factory.StartNew(() =>
{
// loop for about 10s with 10ms step
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(10);
Task.Factory.StartNew(() =>
{
// this is a task created each time you want to update to the UI thread.
this.Text = i.ToString();
}, CancellationToken.None, TaskCreationOptions.None, currentTaskScheduler);
}
return "Finished!";
})
.ContinueWith(t =>
{
// this is a new task will be run after the main task complete!
this.Text += " " + t.Result;
}, currentTaskScheduler);
В течение 10 секунд код отобразит от 1 до 1000, а затем добавит "Готово!". строка в строке заголовка окна. Вы можете видеть, что TaskScheduler - это сложный способ создания обновления потокового потока пользовательского интерфейса, потому что я думаю, что задача должна быть запущена в основном потоке.
Ответ 3
Нет встроенной поддержки для этого, как у BackgroundWorker.
Вы можете напрямую использовать SynchronizationContext; там отличное видео здесь: http://www.rocksolidknowledge.com/ScreenCasts.mvc/Watch?video=TasksAndThreadAffinity.wmv
Автор разрабатывает два решения в этом видео: один использует SynchronizationContext, а другой использует Continuations. Для вашей проблемы продолжения не будут работать, но подход SynchronizationContext будет работать нормально.
P.S. Если вы создаете многоразовый код, то при захвате SynchronizationContext.Current вы должны проверить значение null и (если оно равно null) использовать построенный по умолчанию SynchronizationContext.
UPDATE. Я разместил код для этого в своем блоге. Мое решение на самом деле основано на Task
, который возвращается к потоку пользовательского интерфейса с помощью TaskScheduler
, который использует SynchronizationContext
под ним. В отличие от принятого ответа, это решение будет работать как для WPF, так и для Windows Forms.
Ответ 4
TPL не особенно ориентирован на поддержку пользовательского интерфейса, вы можете (по-прежнему) использовать BackgroundWorker для этого. Что касается отправки или обработки промежуточных результатов, для поддержки этого списка есть новые коллекционные классы (ConcurrentQueue).
Ответ 5
Чтобы сообщить о прогрессе из задачи async, передайте IProgress в метод async. В рамках метода вызовите Report с данными о ходе работы. Вызывающий может решить, как обрабатывать этот отчет о ходе работы (т.е. Игнорировать его или обновлять пользовательский интерфейс).