Генерирование уникальный значений в разных процессах. erlang
От: Аноним  
Дата: 09.05.09 12:11
Оценка:
Такая ситуация:
Есть рекурсивная функция F, внутри которой порождается несколько процессов, затем выполним задачу они умирают, и происходит новый вызов функции, и т.д.

Проблема в том, что в каждом процессе необходимо генерировать несколько чисел (сколько именно, становится известно только внутри процесса, число находится в разумных пределах, т.е. скорее всего не будет превышать 1 000 000, однако могут быть исключения). И вот если из каждого процесса взять все числа то все они должны быть уникальные. При последующем вызове функции F, в нее передается ЧАСТЬ этих чисел и в последствии их использовать уже нельзя.
Как я сейчас это реализую. имеется два вариант:
1) Очень элементарный, беру системное время в микросекундах и из него конструирую число. Мне пока так и не понятно, если система работает на одной машине может ли получится такая ситуация что в разных процессах erlang:now(). вернет одно и тоже значение? Я проводил опыты, вроде бы все значения были уникальные (с разницей в 1-3 микросекунды). Но всё равно уверенности нет, поэтому это первый вопрос.
2) если 1) работает так как мне хотелось бы, то как быть с системой работающей на нескольких машинах? — в этом случае время может сгенерироваться одинаковое. Перестановка времени на каждой машине, конечно неприемлема). Поэтому в данном случае я в каждый процесс запускаю некоторое число (внутри числа генерятся просто добавляя единицу постепенно) след образом: в первый процесс N, во второй N+m, третий N+2*m и т.д. так как всего кол-во чисел в процессе врятли превысит 1 000 000, то m=1 000 000 (однако каким бы m я не взял, всё равно есть хоть и маленькая, но положительная вероятность, что кол-во чисел окажется больше m ив конечном итоге где может произойти роковое дублирование), а при очередном вызове F, я передаю ему параметром новое значение N, равное N+n*(k+1), где k — кол-во созданных процессов.

Как видно, оба подходя имеют некоторые недостатки.
Если ли какие-то более надежные варианты решения такой проблемы? желательно быстродействующие (т.е. генерация числа не должна занимать много времени)
Re: Генерирование уникальный значений в разных процессах. er
От: Курилка Россия http://kirya.narod.ru/
Дата: 09.05.09 12:29
Оценка: 16 (1)
Здравствуйте, Аноним, Вы писали:

А>1) Очень элементарный, беру системное время в микросекундах и из него конструирую число. Мне пока так и не понятно, если система работает на одной машине может ли получится такая ситуация что в разных процессах erlang:now(). вернет одно и тоже значение? Я проводил опыты, вроде бы все значения были уникальные (с разницей в 1-3 микросекунды). Но всё равно уверенности нет, поэтому это первый вопрос.

Может просто доки читать?

А>2) если 1) работает так как мне хотелось бы, то как быть с системой работающей на нескольких машинах? — в этом случае время может сгенерироваться одинаковое. Перестановка времени на каждой машине, конечно неприемлема). Поэтому в данном случае я в каждый процесс запускаю некоторое число (внутри числа генерятся просто добавляя единицу постепенно) след образом: в первый процесс N, во второй N+m, третий N+2*m и т.д. так как всего кол-во чисел в процессе врятли превысит 1 000 000, то m=1 000 000 (однако каким бы m я не взял, всё равно есть хоть и маленькая, но положительная вероятность, что кол-во чисел окажется больше m ив конечном итоге где может произойти роковое дублирование), а при очередном вызове F, я передаю ему параметром новое значение N, равное N+n*(k+1), где k — кол-во созданных процессов.


Вполне себе вариант (непонятно, почему он "другой", если без 1-го работать не может), правда не совсем понятно почему именно целое нужно. Для простых уидов люди используют {node(), now()}
Re: Генерирование уникальный значений в разных процессах. er
От: Курилка Россия http://kirya.narod.ru/
Дата: 09.05.09 12:31
Оценка:
Здравствуйте, Аноним, Вы писали:

[cut]
А>Если ли какие-то более надежные варианты решения такой проблемы? желательно быстродействующие (т.е. генерация числа не должна занимать много времени)

Если процессы создаются не часто (иначе bottleneck получим), то может завести процесс под счётчик, который бы выдавал миллионы?
Re[2]: Генерирование уникальный значений в разных процессах.
От: Аноним  
Дата: 09.05.09 13:28
Оценка:
Здравствуйте, Курилка, Вы писали:


К>Может просто доки читать?



К>Вполне себе вариант (непонятно, почему он "другой", если без 1-го работать не может), правда не совсем понятно почему именно целое нужно. Для простых уидов люди используют {node(), now()}


Что-то мне, даже, как-то неловко стало))
в общем спасибо.
Re[3]: Генерирование уникальный значений в разных процессах.
От: Курилка Россия http://kirya.narod.ru/
Дата: 09.05.09 19:49
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Что-то мне, даже, как-то неловко стало))

Ну сорри, не хотел, если что, а документация у Эрланга многим непривычна (читай неудобна)

А>в общем спасибо.

Ну для этогож и есть форум
Re[2]: Генерирование уникальный значений в разных процессах.
От: thesz Россия http://thesz.livejournal.com
Дата: 10.05.09 10:45
Оценка: +2
К>[cut]
А>>Если ли какие-то более надежные варианты решения такой проблемы? желательно быстродействующие (т.е. генерация числа не должна занимать много времени)

К>Если процессы создаются не часто (иначе bottleneck получим), то может завести процесс под счётчик, который бы выдавал миллионы?


Да в эту функцию F и положить. Она занимается порождением процессов, пусть она и ведёт.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[2]: Генерирование уникальный значений в разных процессах.
От: Gaperton http://gaperton.livejournal.com
Дата: 11.05.09 13:52
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Может просто доки читать?


Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.
Re: Генерирование уникальный значений в разных процессах. er
От: Pzz Россия https://github.com/alexpevzner
Дата: 11.05.09 13:56
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Проблема в том, что в каждом процессе необходимо генерировать несколько чисел (сколько именно, становится известно только внутри процесса, число находится в разумных пределах, т.е. скорее всего не будет превышать 1 000 000, однако могут быть исключения). И вот если из каждого процесса взять все числа то все они должны быть уникальные. При последующем вызове функции F, в нее передается ЧАСТЬ этих чисел и в последствии их использовать уже нельзя.


Если все равно, какие числа, лишь бы не повторялись (кстати, тут надо бы уточнить, что именно должно не повторяться, сами числа, или последовательность), то напрашивается идея воспользоваться криптографическим генератором псевдослучайных чисел. Безотносительно к языку программирования.

А>1) Очень элементарный, беру системное время в микросекундах и из него конструирую число. Мне пока так и не понятно, если система работает на одной машине может ли получится такая ситуация что в разных процессах erlang:now(). вернет одно и тоже значение? Я проводил опыты, вроде бы все значения были уникальные (с разницей в 1-3 микросекунды). Но всё равно уверенности нет, поэтому это первый вопрос.


Я думаю, это очень зависит от resolution системного времени. Больше ведь ерланговскому интерпрататору это время взять неоткуда. А оно, в свою очередь, зависит от операционной системы и железа, на котором система живет.
Re[2]: Генерирование уникальный значений в разных процессах.
От: Gaperton http://gaperton.livejournal.com
Дата: 11.05.09 14:06
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Я думаю, это очень зависит от resolution системного времени. Больше ведь ерланговскому интерпрататору это время взять неоткуда. А оно, в свою очередь, зависит от операционной системы и железа, на котором система живет.


Системное время времени рознь. Под вендой, например, есть как минимум три "времени" (про которые мне известно). "Обычное" (реальная точность до кванта планировщика задач, это порядка 10 миллисекунд), ацкий мультимедийный таймер (хороший таймер, кажется, гарантирована 1 микросекунда, надо линковаться со специальной либой), и performancecounter (с точностью до процессорного такта, тупо считывается состояние проца). Какой хочешь, такой и используй. Вопрос, чем пользуется рантайм. Сильно сомневаюсь, что в рантайме Erlang применяется первый способ.
Re[2]: Генерирование уникальный значений в разных процессах.
От: Курилка Россия http://kirya.narod.ru/
Дата: 11.05.09 14:14
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, Аноним, Вы писали:


А>>1) Очень элементарный, беру системное время в микросекундах и из него конструирую число. Мне пока так и не понятно, если система работает на одной машине может ли получится такая ситуация что в разных процессах erlang:now(). вернет одно и тоже значение? Я проводил опыты, вроде бы все значения были уникальные (с разницей в 1-3 микросекунды). Но всё равно уверенности нет, поэтому это первый вопрос.


Pzz>Я думаю, это очень зависит от resolution системного времени. Больше ведь ерланговскому интерпрататору это время взять неоткуда. А оно, в свою очередь, зависит от операционной системы и железа, на котором система живет.


А зачем гадать, если можно посмотреть, что делается в реальности?
Re[3]: Генерирование уникальный значений в разных процессах.
От: Курилка Россия http://kirya.narod.ru/
Дата: 11.05.09 14:16
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Здравствуйте, Курилка, Вы писали:


К>>Может просто доки читать?


G>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.


А где ты производительность меряешь с вызовами подряд now/0 ? Какой в этом смысл?
Re[4]: Генерирование уникальный значений в разных процессах.
От: Gaperton http://gaperton.livejournal.com
Дата: 11.05.09 14:51
Оценка:
Здравствуйте, Курилка, Вы писали:

К>>>Может просто доки читать?


G>>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.


К>А где ты производительность меряешь с вызовами подряд now/0 ? Какой в этом смысл?


Да замерял как-то свои прототипы для обработки биржевых котировок. Надо было сравнить несколько подходов. Профайлеры часто сильно искажают раскладку, и часто проще вставить тупые замеры. Или есть какой-то способ лучше чем now?
Re[4]: Генерирование уникальный значений в разных процессах.
От: Gaperton http://gaperton.livejournal.com
Дата: 11.05.09 14:51
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Здравствуйте, Gaperton, Вы писали:


G>>Здравствуйте, Курилка, Вы писали:


К>>>Может просто доки читать?


G>>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.


К>А где ты производительность меряешь с вызовами подряд now/0 ? Какой в этом смысл?


Впрочем, в моих замерах все было ГОРАЗДО медленнее микросекунд .
Re[3]: Генерирование уникальный значений в разных процессах.
От: Pzz Россия https://github.com/alexpevzner
Дата: 11.05.09 17:27
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.


В линухе два идущих подряд вызова gettimeofday() (получить время с микросекундной точностью) вернут разные значения. А все потому, что gettimeofday() — системный вызов, а это удовольствие не дешевое.
с
Re[3]: Генерирование уникальный значений в разных процессах.
От: CrystaX Россия https://crystax.me/
Дата: 12.05.09 22:15
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца.


На самом деле там все просто. Есть такое вот место в исходниках (otp_src_R12B-5/erts/emulator/beam/erl_time_sup.c):
/* get a timestamp */
void
get_now(Uint* megasec, Uint* sec, Uint* microsec)
{
    SysTimeval now;
    
    erts_smp_mtx_lock(&erts_timeofday_mtx);
    
    get_tolerant_timeofday(&now);
    do_erts_deliver_time(&now);
    
    /* Make sure time is later than last */
    if (then.tv_sec > now.tv_sec ||
    (then.tv_sec == now.tv_sec && then.tv_usec >= now.tv_usec)) {
    now = then;
    now.tv_usec++;
    }
    /* Check for carry from above + general reasonability */
    if (now.tv_usec >= 1000000) {
    now.tv_usec = 0;
    now.tv_sec++;
    }
    then = now;
    
    erts_smp_mtx_unlock(&erts_timeofday_mtx);
    
    *megasec = (Uint) (now.tv_sec / 1000000);
    *sec = (Uint) (now.tv_sec % 1000000);
    *microsec = (Uint) (now.tv_usec);
}


Вот она, гарантия. Другое дело, что два последовательных вызова now/0 вряд ли дадут на generic OS разницу меньше микросекунды, но гарантия все-таки обеспечивается вышеприведенным кодом.
Re[4]: Генерирование уникальный значений в разных процессах.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 26.05.09 20:27
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, Gaperton, Вы писали:


G>>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.


Pzz>В линухе два идущих подряд вызова gettimeofday() (получить время с микросекундной точностью) вернут разные значения. А все потому, что gettimeofday() — системный вызов, а это удовольствие не дешевое.


Нет, там основные задержки не от системного вызова. Проверяю: написал 100 раз подряд вызов gettimeofday() и выдачу разницы в микросекундах между этими 100 запросами. Результаты:

FreeBSD, таймер i8254 => 415мкс
FreeBSD, таймер ACPI => 420мкс
FreeBSD, таймер TSC => 26мкс
во всех случаях FreeBSD 7.2, не-SMP, мать M2A-VM, проц Athlon64 3500+

Linux, таймер TSC => 6мкс
Linux, таймер HPET => 84мкс
Linux, таймер ACPI => 185мкс
во всех случаях ядро 2.6.25-std-def-alt8.M41.1, мать — что-то Gigabyte, проц Q6600 (TSC на нём идёт одинаково на всех ядрах)

То есть для двух подряд gettimeofday() вполне вероятно получить и одинаковое значение, если правильно считается;)) А доля времени на собственно системный вызов крайне мала, для линукса не более 60нс, а реально меньше, для фряхи не более 260нс, аналогично;) Вывод — стоимость системного вызова сейчас сильно преувеличена.

А вот стоимость внешнего запроса тут значительно больше. i8254 понятно — он сидит на медленной шине (это сейчас не ISA, но тоже тормоз). ACPI (он же PIIX) — притормаживает и его надо три раза подряд спрашивать, потому что защёлки данных нет (у Intel есть документ, как с ним работать). HPET побыстрее, но его дизайн во всём кроме раздачи прерываний придуман в белой горячке. Только TSC не тормозит, к сожалению.

Ну а now(), конечно, "тот ещё" зверь. Фактически он даёт не реальное время, а его эмуляцию с выполнением свойства строгой монотонности. И это время может сильно отличаться от того, что выдаётся в erlang:localtime() или erlang:universal_time(), если часы скачут. К сожалению, вызова типа "а дай мне нормальное внешнее время не перекодируя его в хрен знает что" нету, и для uptime (CLOCK_MONOTONIC) то же самое. Мы поставили в отдалённые планы себе сделать модуль для этого, пока что используем просто now().
The God is real, unless declared integer.
Re[3]: Генерирование уникальный значений в разных процессах.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 26.05.09 20:27
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Здравствуйте, Курилка, Вы писали:


К>>Может просто доки читать?


G>Кстати, это скорее всего означает, серия вызовов now() идущих подряд будет выполняться с частотой не больше мегагерца. Любопытно. Это надо иметь в виду при использовании now в качестве средства замера производительности.


Увы — просто ответ now() начнёт спешить по сравнению с реальным временем.
The God is real, unless declared integer.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.