gettimeofday clock_gettime решение для генерации уникального номера

Мой процесс запускает несколько экземпляров (процессов) и несколько streamов, и все они записываются в одну и ту же базу данных. Как только запрос будет помещен, создается уникальный идентификатор req для записи, которая будет добавлена ​​в проприетарный db. Вот наши ограничения: оно не может превышать 9 символов, должно быть hhmmss в качестве первых 6 символов. Мы решили использовать ms за последние 3 цифры, чтобы заполнить 9 символов, и мы делаем все это, используя gettimeofday (). Тем не менее, при увеличении трафика, теперь есть случаи коллизий, когда несколько запросов помещаются в период ms. Это в сочетании с тем, что gettimeofday () не является точным, вызывает увеличение количества коллизий. Я пытался использовать clock_gettime, но при тестировании это также не так точно, как я заметил из следующей тестовой программы:

  • Мы не могли использовать статические или глобальные переменные из-за проблем с streamами
  • Невозможно использовать случайные числа, поскольку они должны быть последовательными

Цените любую помощь.

#include  int main( int argc, char **argv ) { long i; struct timespec start, stop; double gap; clock_gettime( CLOCK_REALTIME, &start); for (i =0; i< 123456789 ; i++); clock_gettime( CLOCK_REALTIME, &stop); gap = ( stop.tv_sec - start.tv_sec ) + ( stop.tv_nsec - start.tv_nsec ) / 1000000; printf( "%lf ms\n", gap ); return 0; } 

Использование метки времени в качестве уникального идентификатора никогда не будет работать надежно, если вы не ограничитесь только одной транзакцией за самый низкий такт (в этом случае 1 миллисекунда).

Поскольку вы застряли, используя значение времени для первых 6 из 9 байтов, вам нужно попытаться установить как можно больше диапазона в последние 3 байта.

Если вам удастся избежать использования символов ASCII в последних трех байтах, вам следует избегать этого, поскольку это ограничит значения, которые могут иметь большое значение. Если возможно, вы должны попытаться использовать эти байты как 24-битное целое число (диапазон 16777216) и просто каждую операцию увеличивать счетчик. Затем вы можете установить его на 0 каждый раз, когда gettimeofday сообщит вам, что время изменилось. (или вы можете настроить повторяющийся SIGALRM, чтобы сообщить, когда нужно снова позвонить gettimeofday, чтобы обновить ваше время и 0 24-битное целое число).

Если вы вынуждены использовать ASCII печатные символы для этих байтов, тогда все будет немного сложнее. Самый простой способ расширить диапазон этого – использовать шестнадцатеричные, а не десятичные числа. Это увеличивает ваш отображаемый диапазон от 1000 до 4096. Однако вы можете сделать лучше, если используете еще более широкую базу чисел. Если вы применили первые 22 символа алфавита (так же, как и для первых 6 букв, для шести), вы можете представить 32x32x32 значения, 32x32x32 32768. Это будет много транзакций в секунду. Вы можете сделать еще лучше, если вы расширите свой цифровой алфавит еще дальше, но он станет более разрозненным, как и вы, поскольку вы, вероятно, захотите ограничить некоторые символы появлением в значении. Использование представления, с которым strtol или strtoul может легко работать, скорее всего, будет легче программировать.

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

Тип проблемы, которую вы описываете, уже более или менее решен путем выпуска UUID. Это система, которая предназначена для решения всех проблем, которые вы упомянули, и еще нескольких.

Библиотека linux: http://linux.die.net/man/3/uuid

Дополнительная информация доступна здесь: http://en.wikipedia.org/wiki/Universally_unique_identifier

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

Три символа, оставленные для кодирования вещей однозначно, не так уж много. Попытайтесь хотя бы использовать некоторую другую кодировку, такую ​​как base64.

Если вы используете gcc как компилятор, у вас есть локальное хранилище streamов (TLS) в качестве расширения, которое достаточно эффективно. Просто префикс static переменной __thread (или так). Если у вас есть ограничения на phtreads, есть средства для получения также специфичных для streamа ключей pthread_get_key . Но лучше было бы иметь информацию как можно дольше на стеке streamа.

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

  • ваша метка hhmmss как таковая
  • столько бит, что вам нужно, чтобы определить ваши streamи
  • последние биты для каждого серийного номера streamа, как указано выше, которые должны завершаться только после более чем второй секунды

Вы даже можете обманывать и yield stream, который запускает слишком много запросов в течение одной секунды.

Я думаю, вы могли бы дать каждому streamу каждого процесса уникальный идентификатор при запуске, я думаю, это займет только один из трех доступных символов, если у вас нет сотен streamов. Затем вы можете использовать локальный счетчик для каждого streamа, чтобы установить последние два символа (используя base64 или даже больше, в зависимости от того, какие символы разрешены, чтобы получить достаточную амплитуду).

В этой ситуации единственным случаем столкновения может быть, если счетчик streamа обертывается в течение той же секунды.

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