Почему вы так уверены, что WM_PAINT
и другие сообщения Windows перекачиваются, а Parallel.For
или Task.Wait
блокирует поток пользовательского интерфейса?
Следующий простой пример доказывает, что вы ошибаетесь. Форма не окрашивается в красный цвет в течение 15 секунд, тогда как работает Parallel.For
.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFroms_21681229
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.Shown += MainForm_Shown;
}
void MainForm_Shown(object sender, EventArgs e)
{
MessageBox.Show("Before");
this.BackColor = Color.FromName("red");
this.Invalidate();
// the form is not getting red for another 15 seconds
var array = new double[] { 1, 2, 3 };
Parallel.For(0, array.Length, (i) =>
{
System.Threading.Thread.Sleep(5000);
Debug.Print("data: " + array[i]);
});
MessageBox.Show("After");
}
}
}
Вот как выполнять задачи параллельно, сохраняя при этом пользовательский интерфейс отзывчивый:
async void MainForm_Shown(object sender, EventArgs e)
{
MessageBox.Show("Before");
this.BackColor = Color.FromName("red");
this.Invalidate();
// the form is not getting red for another 15 seconds
var array = new double[] { 1, 2, 4 };
var tasks = array.Select((n) => Task.Run(()=>
{
Thread.Sleep(5000);
Debug.Print("data: " + n);
}));
await Task.WhenAll(tasks);
MessageBox.Show("After");
}
Вы могли бы сделать что-то вроде await Task.Factory.StartNew(() => Parallel.For(...))
, но это будет использовать больше, по крайней мере один поток, чем действительно необходимо.
Чтобы понять, что происходит за сценой здесь, вы должны понять, как петля WinForms сообщение работает внутри Application.Run
, как await
дает контроль выполнения обратно в цикл обработки сообщений, а затем получает по-прежнему с помощью WindowsFormsSynchronizationContext
, когда задача имеет завершено. async-await
tag wiki может помочь, он содержит ссылки на некоторые большие, необходимые для чтения ресурсы.
Если вам интересно узнать, как работает перекачка сообщений во время операций блокировки, отметьте this answer.
'Parallel.For' уже блокирует текущий поток до тех пор, пока все задачи не будут выполнены. –
'Parallel.For' не возвращается до его завершения. Если вы завернете его в «Задачу», тогда эта задача будет завершена «точно» в тот же момент времени, в который возвращается «Parallel.For». Вы ничего не добавили. –
Это неправда, сообщения WM_PAINT прибывают обрабатываемыми ... – abenci