воскресенье, 2 ноября 2014 г.

10. ZeroMQ: нуль-копия (Zero-Copy).

(Начало - здесь)

Нуль - копия (Zero-Copy).


API ZeroMQ позволяет отправлять и принимать сообщения напрямую, используя буфера данных приложения, без копирования данных. Эта технология называется нуль - копия, её применение позволяет увеличить производительность в некоторых приложениях.

О нуль-копии следует вспоминать в случае, когда вы отправляете большие блоки памяти (тысячи байт) с высокой частотой.

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

 
  function zmq_msg_init_data(msg: p_zmq_msg_t; data: Pointer; size: size_t;
    ffn: p_zmq_free_fn; hint: Pointer): Integer; cdecl; external libzmq;

Тип p_zmq_free_fn - указатель на функцию типа zmq_free_fn:
type
  p_zmq_free_fn = ^zmq_free_fn;
  zmq_free_fn = procedure(data: Pointer; hint: Pointer); cdecl;


Когда создается сообщение, вы также передаете параметр - функцию, чтобы ZeroMQ смогла вызвать её для освобождения блока данных после завершения передачи сообщения.

Пример такой функции, предполагающий, что буфер представляет собой блок (длиной, скажем, в 1000 байт), выделенный в куче:

procedure my_free (aData : Pointer; aHint : Pointer); cdecl;
begin
  Freemem(aData);
end;

Пример:
procedure my_free(aBuf, aHint : Pointer); cdecl;
begin
  FreeMem(aBuf);
end;


var
  fMsg : zmq_msg_t;
  fData : Pointer;
...
begin
...
    GetMem(fData, 1000);
    FillChar(fData^, 1000, 'z');
    zmq_msg_init_data(@fMsg, fData, 1000, @my_free, nil);
    zmq_msg_send(@fMsg,fSocketSyncService, 0);


Насчет параметра hint:
 free_fn = procedure(data, hint: Pointer); cdecl;

Библиотека ZeroMQ его просто копирует его значение из параметра hint функции
function zmq_msg_init_data( var msg: zmq_msg_t; data: Pointer; size: size_t;
  ffn: free_fn; hint: Pointer ): Integer; cdecl; external libzmq;

Судя по всему, он введен для особых случаев - например, когда требуется передать блок дополнительных данных в процедуру ffn: free_fn.

Еще раз отмечу, что вызывать zmq_msg_close() после отправки сообщения не нужно - libzmq выполнит вызов автоматически, когда сообщение будет отправлено.

Способа сделать нуль-копию на приеме - нет. 
ZeroMQ предоставит вам буфер, который вы можете использовать сколько угодно, но не записывает данные напрямую в буферы вашего приложения.

При записи составных сообщений ZeroMQ отлично работает с нуль-копией. Для обычных сообщений вам понадобилось бы слить несколько сообщений в один буфер, а только потом отправлять. То есть, понадобилось бы выполнить копирование данных. А с ZMQ можно отправить несколько разных буферов, пришедших от разных источников, как отдельные кадры сообщения. Каждое поле отправляется как кадр, отделенный значением длины (префиксом). В приложении это выглядит как последовательность вызовов отправлений или приема. Однако, внутри ядра ZMQ, составное сообщение отправляется и принимается одним системным вызовом, что очень эффективно.

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

Комментариев нет :

Отправить комментарий