Оптимизация альтернатив DateTime.Now - PullRequest
24 голосов
/ 13 октября 2009

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

Во-первых, отказ от ответственности: я понимаю, что понятие "оптимизация DateTime.Now" звучит безумно для некоторых из вас. У меня есть пара преимущественных защит:

  1. Иногда я подозреваю, что люди, которые всегда говорят: «Компьютеры быстры; удобочитаемость всегда важнее оптимизации» часто говорят о том, что они разрабатывают приложения, в которых производительность, хотя и может быть важна , не является критическим . Я говорю о том, что необходимо, чтобы события происходили как можно ближе к мгновенному состоянию, например, в течение наносекунд (в некоторых отраслях это имеет значение * например, высокочастотная торговля в реальном времени).
  2. Даже с учетом этого альтернативный подход, который я опишу ниже, на самом деле вполне читабелен. Это не странный взлом, а простой метод, который работает надежно и быстро.
  3. У нас есть тестов. DateTime.Now - это медленно (условно говоря). Метод ниже - быстрее.

Теперь перейдем к самому вопросу.

По результатам тестов мы обнаружили, что для запуска DateTime.Now требуется примерно 25 тиков (около 2,5 микросекунд). Конечно, это в среднем за тысячи звонков. Похоже, что первый вызов на самом деле занимает значительное количество времени, а последующие вызовы намного быстрее. Но все же, 25 тиков - это среднее.

Однако мы с коллегой заметили, что для запуска DateTime.UtcNow требуется значительно меньше времени - в среднем, всего 0,03 микросекунды.

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

public static class FastDateTime {
    public static TimeSpan LocalUtcOffset { get; private set; }

    public static DateTime Now {
        get { return DateTime.UtcNow + LocalUtcOffset; }
    }

    static FastDateTime() {
        LocalUtcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
    }
}

Другими словами, определите смещение UTC для местного часового пояса один раз - при запуске - и с этого момента используйте скорость DateTime.UtcNow, чтобы получить текущее время намного быстрее с помощью FastDateTime.Now.

Я мог видеть, что это проблема, если смещение UTC изменилось во время работы приложения (например, если приложение работало в течение ночи); но, как я уже говорил, в нашем случае этого не произойдет.

У моего коллеги есть другое представление о том, как это сделать, что мне слишком сложно объяснять здесь. В конечном счете, , насколько я могу судить , оба наших подхода дают точный результат, мой - немного быстрее (~ 0,07 мкс против ~ 0,21 мкс).

То, что я хочу знать, это:

  1. Я что-то здесь упускаю? Принимая во внимание вышеупомянутый факт, что приложение будет работать только в течение периода времени от одной даты, является ли FastDateTime.Now безопасным?
  2. Может кто-нибудь еще подумать о даже более быстром способе получения текущего времени?

Ответы [ 4 ]

26 голосов
/ 13 октября 2009

Не могли бы вы просто использовать DateTime.UtcNow и конвертировать только в местное время, когда данные представлены? Вы уже определили, что DateTime.UtcNow намного быстрее, и это устранит любую неопределенность вокруг DST.

7 голосов
/ 22 июня 2010

Одна разница между результатом

DateTime.Now

и

DateTime.UtcNow + LocalUtcOffset 

- это значение свойства Kind - Local против Utc соответственно. Если полученный DateTime передается сторонней библиотеке, рассмотрите возможность возврата

DateTime.SpecifyKind(DateTime.UtcNow + LocalUtcOffset, DateTimeKind.Local)
5 голосов
/ 16 октября 2016

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

DateTime.UtcNow в 117 раз быстрее, чем DateTime.Now

использование DateTime.UtcNow достаточно, если нас интересует только продолжительность, а не само время. Если все, что нам нужно, - это рассчитать длительность определенной части кода (делая duration= End_time - Start_time), тогда часовой пояс не важен, и достаточно DateTime.UtcNow.

Но если нам нужно само время, тогда нам нужно сделать DateTime.UtcNow + LocalUtcOffset

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

Если мы поместим это вычисление в отдельную функцию / класс, как предложено, то вызов метода замедлит нас еще больше и мы только в 34 раза быстрее.

Но даже в 34 раза быстрее, это много !!!

Короче говоря, Использование DateTime.UtcNow намного быстрее, чем DateTime.Now

Единственный способ улучшить предложенный класс - это использовать встроенный код: DateTime.UtcNow + LocalUtcOffset вместо вызова метода класса

Кстати, пытаясь заставить компилятор компилировать как встроенный, используя [MethodImpl(MethodImplOptions.AggressiveInlining)] не похоже, чтобы ускорить процесс.

2 голосов
/ 13 октября 2009

Ответить в обратном порядке:

2) Я не могу придумать более быстрый путь.

1) Стоит проверить, есть ли в конвейере какие-либо улучшения фреймворка, как они только что объявлены для System.IO

Трудно быть уверенным в безопасности, но это то, что требует многих юнит-тестов. Летнее время приходит на ум. System One, очевидно, очень боеспособен, а ваш нет.

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