Самый эффективный способ отправки изображений между процессами - PullRequest
8 голосов
/ 29 марта 2010

Цель

Эффективно и с очень высокой скоростью передайте изображения, созданные одним процессом, другому процессу. Эти два процесса выполняются на одном компьютере и на одном рабочем столе. Операционная система может быть WinXP, Vista и Win7.

Подробное описание

Первый процесс предназначен исключительно для управления связью с устройством, которое производит изображения. Эти изображения имеют размер около 500x300 пикселей и могут обновляться до нескольких сотен раз в секунду. Второй процесс нуждается в этих изображениях для их обработки. Первый процесс использует сторонний API для рисования изображений с устройства на HDC. Этот HDC должен быть предоставлен мной.

Примечание. Между двумя процессами уже открыто соединение. Они общаются через анонимные каналы и совместно используют представления файлов, отображенных в памяти.

Мысли

Как бы я достиг этой цели с минимально возможной работой? И я имею в виду как работу для компьютера, так и для меня (конечно;)). Я использую Delphi, так что, возможно, для этого есть какой-то компонент? Я думаю, что я всегда мог нарисовать на HDC любого компонента изображения, сохранить содержимое в потоке памяти, скопировать содержимое через файл отображения памяти, распаковать его на другой стороне и нарисовать там в целевой HDC. Я также читал об интерфейсе IPicture, который можно использовать для маршалинга изображений. Мне нужно как можно быстрее, поэтому чем меньше накладных расходов, тем лучше. Я не хочу, чтобы машина подверглась стрессу, просто скопировав несколько изображений.

Какие у тебя идеи? Я ценю все мысли об этом!

Ответы [ 5 ]

11 голосов
/ 29 марта 2010

Использовать сопоставленный файл памяти .

Ссылка на Delphi приведена в Отображенные в память файлы в Delphi и Общая память в Delphi .

Для более универсального подхода вы можете использовать каналы или отправлять растровые данные через TCP. Это позволит вам при необходимости легче распределять данные изображения между узлами.

4 голосов
/ 29 марта 2010

Используйте общую память для передачи данных изображения и что-то еще (именованные каналы, сокеты, ...) для координации передачи.

3 голосов
/ 29 марта 2010

В некоторых случаях вы можете передавать дескрипторы HBITMAP через процессы. Я видел это раньше (да, на XP / Vista) и был удивлен, как и все остальные в команде, когда один из моих коллег показал мне.

Если память мне не изменяет, я считаю, что она будет работать, если HBITMAP был выделен одной из функций GDI (CreateBitmap, CreateCompatibleBitmap, CreateDIBitmap и т. Д.). Ручки HBIMAP, созданные LoadBitmap, не будут работать, так как это просто указатель на внутрипроцессный ресурс.

Это, и я думаю, что когда вы делитесь HBITMAP с другим процессом, не пытайтесь делать с ним что-то особенное, кроме обычных операций BitBlt.

По крайней мере, это то, что я помню. Нам повезло, потому что наши графические библиотеки уже написаны для управления всеми изображениями как HBITMAP.

YMMV

1 голос
/ 01 апреля 2010

Хорошо, похоже, что файлы и каналы с отображением в памяти - правильный путь. Это не так уж плохо, потому что два процесса уже совместно используют MMF и два канала (для двунаправленной связи). Единственное, что осталось решить - как передать данные с минимальным количеством операций копирования.

Дизайн, который работает довольно хорошо, выглядит следующим образом (последовательный поток):

Процесс 1 (требуется изображение)

  • подать сигнал процессу 2 (через канал 1) на сохранение изображения в общей памяти
  • иди спать и жди ответа (блокировка чтения из канала 2)

Процесс 2 (предоставляет изображения)

  • при получении сигнала (по каналу 1) просыпается и сообщает аппаратному устройству выполнить запись в HDC 1 (это поддерживается общей памятью, см. Ниже)
  • подать сигнал процессу 1 (по трубопроводу 2)
  • иди спать и жди новой работы (по трубе 1)

Процесс 1 (требуется изображение)

  • при сигнале (по каналу 2) просыпаются и рисуют из разделяемой памяти в пункт назначения HDC 2

Теперь для передачи изображения через разделяемую память (моей целью было использовать не более одной дополнительной операции копирования):

Процесс 2 создает HBITMAP через CreateDIBSection и предоставляет дескриптор сопоставления файла и смещение отображенного представления. Таким образом, данные изображения живут в общей памяти. Это создает HBITMAP, который выбирается в HDC 1 (который также создается процессом 2) и который теперь будет использоваться процессом 2.

Процесс 1 использует StretchDIBits с указателем на память отображенного представления (как описано здесь ). Это, кажется, единственная функция для получения битов из памяти непосредственно в другой HDC (в данном случае HDC 2). Другие функции сначала скопируют их в некоторый промежуточный буфер, прежде чем вы сможете перенести их оттуда в конечный HDC.

Так что в итоге кажется, что биты, которые нужно передать, примерно вдвое больше, чем в начале. Но я думаю, что это так же хорошо, как и до тех пор, пока не будет возможно совместное использование дескрипторов GDI между процессами.

Примечание: я использовал каналы вместо сигналов, потому что мне тоже нужно передать некоторые дополнительные данные.

0 голосов
/ 29 марта 2010

Как я вижу, у вас есть два варианта:

  1. Передача только дескриптора / указателя изображения другому процессу, поэтому оба процесса работают только с одной коллекцией изображений.
  2. Скопируйте содержимое изображения в другой процесс и с этого момента работайте над копией.

Какой подход лучше, зависит от вашего дизайна. Лучшим инструментом для обоих подходов будут «файлы с отображением в памяти» или «именованные каналы». Это самое быстрое, что вы можете получить. Файлы с отображением в памяти, вероятно, являются самой быстрой формой межпроцессного взаимодействия, но имеют недостаток, заключающийся в том, что в них не заложена парадигма «клиент-сервер». Таким образом, вы должны синхронизировать доступ к MMF самостоятельно. Именованные каналы, с другой стороны, почти такие же быстрые, но в них заложена парадигма клиент-сервер. Разница в скорости происходит в основном от этого.

Теперь, из-за скорости обмена обновлениями, первый подход мог бы быть лучше, но тогда вы должны следить за синхронизацией между процессами, чтобы они не считывали / записывали в одно изображение одновременно. Также можно использовать какой-то вид кэширования или другие умные методы, чтобы вы сократили трафик до минимума. При таком высоком уровне связи всегда целесообразно искать способы снижения этого уровня, если это возможно.

Для очень быстрой реализации IPC на основе именованных каналов вы можете использовать мою реализацию IPC . Он ориентирован на сообщения, поэтому вам не нужно беспокоиться о технических деталях трубы. Это также использует пул потоков за сценой и имеет минимальные дополнительные издержки. Вы можете провести стресс-тестирование и убедиться в этом (типичное сообщение занимает полный цикл запроса-ответа клиента-сервера).

...