понедельник, 12 ноября 2012 г.

Деструкторы для замыканий, часть 2

Первая часть.

А если замыкание используется лишь в самом начале блока, то рациональней сразу после использования освободить ресурсы, а не в конце.

 use Carp;

 sub with_foo {
  my $foo = shift;
  my $sub = shift;
  print "INIT\n";
  my $destroyed = 0;
  my $closure = sub {
   unless ($destroyed) {
    $foo += shift;
    print $foo, "\n";
   } else {
    carp "Already destroyed";
   } 
  };
  my $destructor = sub {
   unless ($destroyed) {
    $destroyed = 1;
    print "DESTROY\n";
   } else {
    carp "Already destroyed";
   }
  };
  eval { $sub->($closure, $destructor) };
  $destructor->() unless $destroyed;
 }
 
 {
  with_foo(3, sub {
   my ($foo, $_foo) = @_;
   $foo->(1);
   $foo->(1);
   $foo->(2);
   $foo->(2);
   $_foo->();
   print "END\n"
  });
 }

четверг, 27 сентября 2012 г.

Very simple Multithreading with Continuation-passing style

{
 my @cc = ();

 sub cc(&) {
  my ($sub) = @_;
  push @cc, $sub;
 }

 sub cc_run() {
  while (my $sub = shift @cc) {
   $sub->();
   sleep 1;
  }
 }
}


sub first {
 my ($thread) = @_;
 print "$thread: 1 first\n";
 cc { third($thread) };
}

sub second {
 my ($thread) = @_;
 print "$thread: 2 second\n";
 cc { fourth($thread) };
}

sub third {
 my ($thread) = @_;
 print "$thread: 3 third\n";
 cc { first($thread) };
}

sub fourth {
 my ($thread) = @_;
 print "$thread: 4 fourth\n\n";
 cc { second($thread) };
}


cc { first("+") };
cc { second("*") };
cc_run;

понедельник, 24 сентября 2012 г.

Добавил quit в IPC::MPS

Очень плотно и давно использую модуль IPC::MPS для распараллеливания задач, но только сейчас понадобился выход из receive блока (из вложенного receive). Поэтому добавил подпрограмму quit.

пятница, 22 июня 2012 г.

Сравниваем MongoDB с MySql как Key-Value

Уговорили меня включить MongoDB в сравнение баз данных для Key-Value (смотрите PostgreSQL, MySql and MariaDB as Key-Value storage).

Оказалось, что MongoDB использует для хранения данных отображение памяти в файлы, поэтому для баз больше 2G, надо использовать 64-bit архитектуру.
После того как узнал это, надо было сразу выкинуть MongoDB, но все таки решил проложить. Поставил FreeBSD 9.0 amd64 и для чистоты эксперимента прогнал некоторые тесты для MySql и PostgreSql.

Решил тестировать только на коротких ключах (подробности смотрите тут BerkeleyDB и TokyoCabinet).

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

Результаты:
Чтение где-то в 2 раза медленней, чем у MySql.
Вставка также медленней, но периодически скорость вставки настолько замедляется, что даже не удается вставить запись в течении 30 секунд!

Поиск информации интернете показал, что это проблеме не связана с FreeBSD и наблюдается и под Linux.
А может это такой Perl модуль? Но ведь автор его является также разработчиком ядра MongoDB!

Некоторые значения полей отличаются после извлечения из базы. Может MongoDB чудит, считая, что это utf8.

Выводы.
MongoDB, с диском надо работать как с диском, а не как с памятью!
MySql и PostgreSql - фавориты. А в PostgreSql 9.2 появился index only scan, - так что PostgreSql еще повысил свою привлекательность.

Как люди работают с MongoDB? Или у них базы маленьких относительно оперативной памяти?

пятница, 8 июня 2012 г.

Одна история с Perl, Coro и IPC::MPS

Где-то два года назад была сделана некоторая система обработки получаемой из Web информации. Так как была сделана грамотно, то легким движением руки превращалась либо в многопроцессный, либо в основанный на сопрограммах вариант. В первом случае использовался модуль межпроцессного взаимодействия на основе сообщений IPC::MPS и EV, а во втором - Coro и EV.

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

Долгие выяснения, что не так с Coro вариантам ни к чему не привели. И лишь сегодня на рассвете я понял, что "ларчик просто открывался"! Я просто перегрузил Coro вариант, посчитав, что раз сопрограммы легкие, то можно одновременно обрабатывать задание побольше.

Рассмотрим этот ситуацию подробней. Время выполнения задания равно сумме времени получения информации и времени обработки ее. Поскольку сопрограммы выполняются в рамках одного процесса, то оптимальное количество одновременно выполняемых заданий равно результату деления времени получения информации на время ее обработки. Если оно меньше, то процесс будет простаивать, если больше, что вырастет время выполнения задания, пропорционально этому превышению.

У меня интернет медленный, поэтому 100 сопрограмм показывали отличный результат.
У хостера интернет быстрый, поэтому у него Coro вариант выполнял заданий лишь в 2 раза больше, чем однопоточный. Но при этом время выполнения заданий было больше раз в 50. Перегрузил.

То есть, вариант с сопрограммами оптимален для медленных каналов связи или неторопливой второй стороны.

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

Ну, а если процессоров много, что многопроцессорный вариант находиться вне конкуренции. Кончено, самую высокую производительность покажет гибрид многопроцессного варианта и варианта с сопрограммами. Но если памяти на сервере хватает, каналы быстрые и источники информации резвые, то, наверно не стоит тратить время на гибрид. Хотя в каждом конкретном случае необходим индивидуальных подход.

Разумеется, если не ты задаешь управляешь интенсивность работы системы, а должен быть готов обработать запросы множества медленных клиентов, то тут без событийной машины или сопрограмм не обойтись.

вторник, 5 июня 2012 г.

IPC::MPS was updated for Multiplicative Agent

IPC::MPS was updated for Multiplicative Agent.

Changes:
- connected flag in NODE_CLOSED
- your own pack and unpack functions, instead of Storable

First change is need to distinguish "Cannot connect to node" and "Node closed" states.