Вопрос:

Параллельное рисование Windows Forms

c# winforms graphics parallel-processing runtime-error

549 просмотра

1 ответ

119 Репутация автора

Можно ли рисовать на панели с помощью Parallel.Forпетли? У меня есть многомерный массив двойников, double[][] plantsи я хочу рисовать столбцы параллельно, где каждая запись в массиве рисуется в виде прямоугольника в сетке на панели.

На линии с grapahics.FillRectangle(), я продолжаю получать эту ошибку, когда я пытаюсь:

Исключение типа «System.InvalidOperationException» произошло в System.Drawing.dll, но не было обработано в коде пользователя

Дополнительная информация: Объект в настоящее время используется в другом месте.

Вот код, который я использую:

    Parallel.For(0, simWidth, i =>
        {
            Color plantColor;
            RectangleF plantRectangle= new Rectangle();
            SolidBrush plantBrush = new SolidBrush(Color.Black);
            for (int j = 0; j < simHeight; ++j)
            {
                int r, g = 255, b;
                r = b = (int)(255 * (Math.Tanh(simulation.plants[i, j]) + 1) / 2.0);
                plantColor = Color.FromArgb(100, r, g, b);
                plantBrush.Color = plantColor;
                plantRectangle.Location = new PointF(i * cellSize, j * cellSize);
                graphics.FillRectangle(plantBrush, plantRectangle);
            }

            plantBrush.Dispose();
        });

Я думаю, что происходит, что графический объект не может обрабатывать несколько вызовов одновременно. Есть ли способ обойти это? Я пытался создать локальную ссылку на графический объект при каждом параллельном вызове, но это не сработало.

Автор: Austin S. Источник Размещён: 08.04.2017 01:45

Ответы (1)


2 плюса

51513 Репутация автора

Решение

Можно ли рисовать на панели с помощью цикла Parallel.For?

Нет, никоим образом не было бы полезно.

Объекты пользовательского интерфейса, такие как Panel, имеют «сходство потоков». То есть они принадлежат определенному потоку и должны использоваться только в этом потоке.

Объекты GDI +, такие как ваш Graphicsобъект (вы не говорите, где вы получили этот объект, но есть надежда, что он был передан вам PaintEventArgs... если нет, у вас есть другие недостатки дизайна в вашем коде), могут быть более прощающими, но не поточными безопасный. Вы можете добавить синхронизацию вокруг фактического использования объекта, но это медленная часть. Их сериализация сведет на нет большинство преимуществ параллелизма в коде.

Ваш вопрос не дает понять, было ли ваше использование Parallelздесь даже реальной попыткой решить какую-то конкретную проблему с производительностью, не говоря уже о том, чем на самом деле была эта проблема. Существует множество вопросов с ответами по переполнению стека, в которых обсуждаются различные методы повышения производительности рендеринга в коде Windows Forms.

Как правило, большинство из этих методов включают в себя максимально возможное сокращение общего объема работы, выполняемой путем кэширования. Исходя из кода, который вы показали, вы можете сделать по крайней мере две вещи:

  1. Кэшируйте вычисления для прямоугольников и цветов. Вы даже можете выполнить эту часть вычисления Parallelпри изменении базовых параметров.
  2. Нарисуйте все в Bitmapобъект. Это должно быть сделано однопоточным, но а) это не нужно делать в потоке пользовательского интерфейса, которому принадлежат ваши объекты пользовательского интерфейса, и б) вы (опять же) можете сделать это только один раз, при изменении базовых параметров. Нарисовав в Bitmap, вы можете просто нарисовать Bitmapобъект, когда Paintпроисходит событие, вместо того, чтобы перерисовывать все с нуля.
Автор: Peter Duniho Размещён: 08.04.2017 02:05
Вопросы из категории :
32x32