обеспечение модели асинхронного программирования: Должен я? и если так, это должен быть VerbAsync () или BeginVerb ()?

Я одолжил некоторые идеи от других создать мое решение. Я использую встроенный код для игнорирования выходных и американских федеральных праздников. В моей среде EndDate может быть пустым, но он никогда не будет предшествовать StartDate.

CREATE FUNCTION dbo.ufn_CalculateBusinessDays(
@StartDate DATE,
@EndDate DATE = NULL)

RETURNS INT
AS

BEGIN
DECLARE @TotalBusinessDays INT = 0;
DECLARE @TestDate DATE = @StartDate;


IF @EndDate IS NULL
    RETURN NULL;

WHILE @TestDate < @EndDate
BEGIN
    DECLARE @Month INT = DATEPART(MM, @TestDate);
    DECLARE @Day INT = DATEPART(DD, @TestDate);
    DECLARE @DayOfWeek INT = DATEPART(WEEKDAY, @TestDate) - 1; --Monday = 1, Tuesday = 2, etc.
    DECLARE @DayOccurrence INT = (@Day - 1) / 7 + 1; --Nth day of month (3rd Monday, for example)

    --Increment business day counter if not a weekend or holiday
    SELECT @TotalBusinessDays += (
        SELECT CASE
            --Saturday OR Sunday
            WHEN @DayOfWeek IN (6,7) THEN 0
            --New Year's Day
            WHEN @Month = 1 AND @Day = 1 THEN 0
            --MLK Jr. Day
            WHEN @Month = 1 AND @DayOfWeek = 1 AND @DayOccurrence = 3 THEN 0
            --G. Washington's Birthday
            WHEN @Month = 2 AND @DayOfWeek = 1 AND @DayOccurrence = 3 THEN 0
            --Memorial Day
            WHEN @Month = 5 AND @DayOfWeek = 1 AND @Day BETWEEN 25 AND 31 THEN 0
            --Independence Day
            WHEN @Month = 7 AND @Day = 4 THEN 0
            --Labor Day
            WHEN @Month = 9 AND @DayOfWeek = 1 AND @DayOccurrence = 1 THEN 0
            --Columbus Day
            WHEN @Month = 10 AND @DayOfWeek = 1 AND @DayOccurrence = 2 THEN 0
            --Veterans Day
            WHEN @Month = 11 AND @Day = 11 THEN 0
            --Thanksgiving
            WHEN @Month = 11 AND @DayOfWeek = 4 AND @DayOccurrence = 4 THEN 0
            --Christmas
            WHEN @Month = 12 AND @Day = 25 THEN 0
            ELSE 1
            END AS Result);

    SET @TestDate = DATEADD(dd, 1, @TestDate);
END

RETURN @TotalBusinessDays;
END
5
задан Community 23 May 2017 в 10:32
поделиться

3 ответа

Почему вы рассматриваете возможность предоставления асинхронного API?

Привязаны ли операции API к вводу-выводу или процессору? (причина, по которой требуется много времени из-за ожидания завершения ввода-вывода, или это просто загрузка ЦП?)

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

Самая веская причина для предоставления асинхронного API - это операции, связанные с вводом-выводом. Вместо того, чтобы связывать потоки для ожидания операций ввода-вывода с высокой задержкой, предпочтительно использовать асинхронный ввод-вывод. Это может особенно повлиять на масштабируемость системы. Например, если у вас был сервер, блокирующий одну синхронную операцию ввода-вывода, это не слишком большая проблема - вы просто связываете один поток. Тем не менее, выполняйте 1000 одной и той же операции одновременно, и вы связываете 1000 потоков (и если память обслуживает 1 МБ на поток для стека) только для ожидания завершения операций, которые занимают несколько циклов ЦП. Конечный результат - у вас простаивает ЦП, но вы потребляете ресурсы.

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

Если, например, вы пишете библиотеку шифрования, то, даже если операции могут занять много времени, там ' Вероятно, нет необходимости предоставлять асинхронный API - все равно это связано с процессором. И, как уже упоминалось, пользователь может сделать его асинхронным.

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

Предоставление асинхронного API, который затем Внутренние вызовы синхронных операций ввода-вывода бессмысленны (хотя я видел, как это делается). Создает иллюзию масштабируемости, но ... нет!

Когда выйдет .NET 4.0, кое-что из этого может стать немного проще (хотя, судя по тому, что я видел, это все равно будет сложно).

А пока вы можете проверить библиотеку асинхронного перечислителя Джеффри Рихтера, которая может помочь (в некоторой степени) упростить это:

Джеффри Рихтер о своем асинхронном перечислителе

Библиотека потоковой передачи, включая асинхронный перечислитель

Hope это помогает,

Предоставление асинхронного API, который затем выполняет внутренние вызовы синхронных операций ввода-вывода, отчасти бессмысленно (хотя я видел, как это было сделано). Создает иллюзию масштабируемости, но ... нет!

Когда выйдет .NET 4.0, кое-что из этого может стать немного проще (хотя, судя по тому, что я видел, это все еще будет сложно).

А пока вы можете проверить библиотеку асинхронного перечислителя Джеффри Рихтера, которая может помочь (несколько упростить):

Джеффри Рихтер о своем асинхронном перечислителе

Библиотека Power threading, включая асинхронный перечислитель

Hope это помогает,

Предоставление асинхронного API, который затем выполняет внутренние вызовы синхронных операций ввода-вывода, отчасти бессмысленно (хотя я видел, как это было сделано). Создает иллюзию масштабируемости, но ... нет!

Когда выйдет .NET 4.0, кое-что из этого может стать немного проще (хотя, судя по тому, что я видел, это все равно будет сложно).

А пока вы можете проверить библиотеку асинхронного перечислителя Джеффри Рихтера, которая может помочь (в некоторой степени) упростить это:

Джеффри Рихтер о своем асинхронном перечислителе

Библиотека потоковой передачи, включая асинхронный перечислитель

Hope это помогает, Фил.

ПРИМЕЧАНИЕ. Если вы собираетесь реализовать асинхронный API, я бы рекомендовал предоставить его через API IAsyncResult «классическое начало / конец». Причина в том, насколько я помню, он должен гораздо лучше интегрироваться с параллельной библиотекой задач .NET 4.0.

6
ответ дан 14 December 2019 в 01:12
поделиться

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

Когда, например, выпущен .NET 4, параллельная библиотека задач будет использовать синхронный объект асинхронно тривиальная «задача» - это означает, что легко просто написать одну версию вашего программного обеспечения и разрешить ее использование асинхронно или синхронно. Сегодня довольно просто использовать пул потоков.

Однако, если ваш метод по своей природе будет ожидать чего-то вне вашего контроля (например, сети), то наличие асинхронных методов имеет решающее значение. В этом случае, я думаю, должны поддерживаться оба варианта, оба Begin * () / End * () и * Async () / * завершены. У обоих шаблонов есть свое применение, и оба легко реализовать.


Если вы посмотрите на страницу MSDN по асинхронному программированию , там есть хороший ключ к размышлениям, который должен помочь вам решить, имеет ли это смысл :

Асинхронные операции обычно используются для выполнения задач, для выполнения которых может потребоваться много времени

Обратите внимание на слово «может». Для меня это ключ при определении, должен ли метод быть асинхронным. Если задача ожидает чего-то другого, и это может занять много времени, или может немедленно вернуться, и это вне моего контроля, то это должно быть асинхронным.

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

 ThreadPool.QueueUserWorkItem( (o) => { DoWork(); }, null);

Однако, если вызывающий объект уже работает в фоновом / отдельном потоке, проще использовать его синхронно. Задачи в .NET 4 делают это еще проще:

 var result = Task<ReturnType>.Factory.StartNew( () => DoWork() );
 // It'll run, and if you want to do EndInvoke, you can do result.Result
1
ответ дан 14 December 2019 в 01:12
поделиться
  1. Я не согласен. Если вы знаете , что делаете. Используйте его!

  2. В Руководстве по проектированию фреймворка рекомендуется использовать асинхронный шаблон на основе событий для высокоуровневые API и классический асинхронный шаблон для низкоуровневых API.

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

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

2
ответ дан 14 December 2019 в 01:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: