Windows / C # системный генератор последовательных чисел? - PullRequest
2 голосов
/ 14 апреля 2009

Есть ли управляемый генератор последовательных чисел на уровне системы? DateTime.Now.Ticks не будут выполняться, потому что операции, которые я выполняю, иногда выполняются более одного раза за тик.


Пояснения к требованиям:

  • Процесс независимый - на самом деле есть только один процесс, который будет обращаться к нему.
  • Производительность имеет решающее значение! Это используется для регистрации показов на рекламном сервере, который может достигать 1k / sec

Это должно быть одно из следующих:

  • 4-байтовый последовательный номер, который сбрасывает каждый тик
  • 12-байтовое последовательное число - по существу, добавление 4 байтов гранулярности к DateTime

Ответы [ 7 ]

6 голосов
/ 14 апреля 2009

Нет тех, которые предназначены для этого, но вы можете использовать System.Diagnostics.PerformanceCounter . Вы также можете использовать Реестр, но вам нужно будет сериализовать доступ для чтения / записи по всем процессам.

System.Diagnostics.PerformanceCounter pc 
    = new System.Diagnostics.PerformanceCounter("SeqCounter", "SeqInstance");
long myVal=pc.Increment();

Редактировать

Чем больше я думаю об этом, тем лучше. Инкремент увеличит счетчик на 1 посредством атомарной операции, которая должна работать во всех процессах системы.

Редактировать

Исходя из ваших правок, я бы не рекомендовал использовать счетчик производительности. Счетчик производительности был способом объединить несколько процессов. Я не уверен, как закодирована внутренняя реализация.

Почему вы не можете просто использовать статическую переменную и увеличивать ее? Вам нужно будет что-то заблокировать, если вы хотите, чтобы это было поточно-ориентированным.

System.Threading.Interlocked.Increment

К вашему сведению: если вы используете длинную версию в 32-битной системе, она не обязательно будет поточно-ориентированной.


Редактирование, чтобы показать реализацию, которую я использовал (DS):

public static class Int32Sequencer
{
    private static Int32 lastSequence = Int32.MinValue;
    private static Object lockObject = new Object();
    public static Int32 GetNextSequence()
    {
        lock (lockObject)
        {
            unchecked { lastSequence++; }
            return lastSequence;
        }
    }
}
1 голос
/ 14 апреля 2009

Guid настолько близок, насколько вы собираетесь, но это «уникально» и не обязательно последовательно. Если вы действительно хотите последовательно выполнять несколько процессов на системном уровне, вам, вероятно, придется свернуть свой собственный.

EDIT:

Хорошо, поэтому из ваших новых требований я буду предполагать:

  1. Только один процесс должен выполнять работу
  2. Вы добавляете в базу данных

Итак, вот что я бы порекомендовал:

  1. При запуске процесса запросить в БД последнее (наибольшее) значение (0, если его нет).
  2. Используйте простую длину и приращение для каждой строки БД. Вы захотите вставить данные из-за высокой скорости передачи данных.

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

0 голосов
/ 14 апреля 2009

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

Первое, что я сделаю, это напишу тестовую программу, которая породила большое количество потоков, каждый из которых неоднократно вызывал функцию приращения блокировки, такую ​​как опубликованная Дэниелом Шаффером. Это позволит вам найти порог, когда ваше приложение начинает работать, где оно тратит больше времени на ожидание Monitor.Enter, чем на что-либо еще.

Если это окажется проблемой - и я бы поспорил, что если объемы, о которых вы говорите, реальны, то это произойдет, - тогда вы должны заставить каждый поток поддерживать свой собственный последовательный счетчик, что можно сделать, пометив поле счетчика с ThreadStaticAttribute. Затем вы можете генерировать уникальные идентификаторы из комбинации идентификатора потока и счетчика.

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

Это явно не тривиально для записи (или, что более важно, для тестирования), поэтому я определенно рекомендую доказать, что это необходимо в первую очередь.

0 голосов
/ 14 апреля 2009

Мне нравится опция базы данных просто для безопасности. Убедитесь, что вы установили монстр SQL-сервер с достаточной пропускной способностью между серверами и достаточным объемом памяти. Система, подобная этой, была внедрена в первой компании, в которой я когда-либо работал (еще до того, как я стал программистом), и она была очень хитрой. Вы можете сражаться, чтобы измерить это.

Другой вариант - внедрить в ваш код одноэлементную функцию ... при условии, что ее будет вызывать только один домен приложения. МОЖЕТ быть немного быстрее, чем поездка по базе данных. Однако, если вы все равно собираетесь записывать эти данные в базу данных ... Как насчет объединения двух ... Запустите синглтон для скорости, а затем запишите в базу данных, когда позволят ресурсы.

Опять же, если последовательное требование не такое сильное, лучшим вариантом будет Guid.

0 голосов
/ 14 апреля 2009

Здесь есть статья, которая дает некоторые детали для сервера sql: Последовательные GUID в SQL Server Этот метод используется для минимизации разбиения страницы из-за случайности GUID. Может быть, эта ссылка даст вам несколько советов или идей.

0 голосов
/ 14 апреля 2009

Я думаю, нам нужно узнать немного больше о том, что вы ищете. Не могли бы вы немного прояснить свой вопрос? В частности, услуга ...

  • Нужно работать со всеми процессами, одним процессом или конкретным пользователем?
  • Должны ли числа быть уникальными или просто последовательными?

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

Нужна последовательная группа чисел для всех процессов в системе

AFAIK, такого сервиса не существует. Нужно писать довольно легко, но заставить его работать во всех процессах довольно сложно.

Требуется уникальная последовательная группа чисел для всех процессов в системе

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

Нужен метод получения уникальных значений в системе

Как отметили несколько других пользователей, лучшим выбором является экземпляр System.Guid. Вы можете создать новый, используя Guid.NewGuid (). Почти для всех целей их можно считать уникальными, но не последовательными.

0 голосов
/ 14 апреля 2009

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

...