Есть код:
string oa = "";
Parallel.ForEach(richTextBox1.Lines, async item =>
{
oa = await Task.Factory.StartNew(
() => Wor.SomeLongOperation(item),
TaskCreationOptions.LongRunning)
+"\n";
richTextBox2.AppendText(oa);
});
У нас "многопоточность", из-за которой происходит конфликт потоков в записи в rich
в этой строке richTextBox2.AppendText(oa);
Как можно сделать так, чтобы сохранить "многопоточность", но всё же результаты записывались в rich
?
Дело в том, что тело функции, которую вы передаете в Parallel.ForEach()
выполняется в других потоках. Внутри этой функции вы обращаетесь к UI-компоненту. Но UI-компоненты позволяют с работать с собой только в том же потоке, в котором они были созданы. Используя проверку IsInvokeRequired
и вызов Invoke()
, вы "перенаправляете" обращение к компоненту в главный (UI) поток и таким образом решаете проблему.
Кроме того, как указали в комментариях, у вас в коде "масло масляное". Дело в том, что вызов Task.Factory.StartNew()
выполняет переданную ему функцию в отдельно потоке. Однако этот вызов уже происходит в отдельном потоке, поскольку вы используете Parallel.ForEach()
. К этому добавляется еще проблема обработки исключений: делегат, который вы передаете в Parallel.ForEach()
представляет собой async void
и опасен тем, что вы либо не узнаете о возникшем исключении, либо узнаете, но будет поздно -- процесс упадет.
Нужно либо убрать вызов Task.Factory.StartNew()
(внешняя переменная вам при этом тоже не нужна):
Parallel.ForEach(richTextBox1.Lines, item =>
{
var oa = Wor.SomeLongOperation(item) + "\n";
// вызов richTextBox2.AppendText(oa) через Invoke
});
Либо убрать Parallel.ForEach()
(этот вариант будет работать медленнее, потому что мы выполняем долгую операцию в другом потоке одну за другой, а не сразу пачкой, как это происходит в случае с Parallel.ForEach()
):
foreach (var item in richTextBox1.Lines)
{
var oa = await Task.Factory.StartNew(
() => Wor.SomeLongOperation(item),
TaskCreationOptions.LongRunning)
+"\n";
richTextBox2.AppendText(oa);
};
Также для подобного кода как правило принято разделять шаг "делаем что-то в отдельном потоке" и шаг "выводим результат на UI". Например, если пользоваться async/await, на помощь придет класс Progress<T>
.
Проблема решена, дописываю с помощью функции:
public void AddText(string text)
{
if (this.richTextBox1.InvokeRequired)
{
Action<string> updaterdelegate = new Action<string>(AddText);
try
{
this.Invoke(updaterdelegate, new object[] { text });
}
catch (ObjectDisposedException ex) { }
}
else
{
richTextBox2.Text += text;
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Доброго времени сутокВозникла следующая проблема, есть XML файл, у меня получается его считать и записать данные в ComboBox, хотелось что бы при...
Как сделать какое либо действие на клавишу ESC если программа свернута?
У меня есть взятая из буфера обмена скопированная из браузера 194 и она не конвертируется, пишет