Контроллер не асинхронный метод мешает другим пользователям войти, когда используется или заблокирован? - PullRequest
0 голосов
/ 15 мая 2019

У меня есть вопрос новичка о методах контроллера в ASP.Net Core. У меня есть две разные реализации ниже, одна синхронная, а другая асинхронная.

Вопрос. Мне кажется, я понимаю разницу между синхронизацией и асинхронностью, но когда дело доходит до ввода метода контроллеров, ASP.Net блокирует всех пользователей от входа в метод синхронизации, если другой пользователь находится внутри него и все еще находится в нем. процесс прохождения через него?

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

То есть я должен использовать вызовы асинхронных контроллеров почти везде? Если я специально не хочу заблокировать другого пользователя!

Вот асинхронный

    [HttpPost]
    public async Task<IActionResult> PostRecordAsync([FromBody] Record record)
    {
        record = await RecordsContext.PostRecordAsync(_context, record);
        return Ok(record);
    }

    public static async Task<Record> PostRecordAsync(MpidDbContext context, Record record)
    {
        context.Records.Add(record);
        await context.SaveChangesAsync();
        return record;
    }

и не асинхронный

    [HttpPost]
    public ActionResult PostRecord([FromBody] Record record)
    {
        record = RecordsContext.PostRecord(_context, record);
        return Ok(record);
    }

    public static Record PostRecord(MpidDbContext context, Record record)
    {
        context.Records.Add(record);
        context.SaveChanges();
        return record;
    }

1 Ответ

1 голос
/ 15 мая 2019

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

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

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

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

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

При работе с ASP.Net Core вам также нужно быть осторожным с асинхронным кодом, поскольку он работает без контекста синхронизации. В коде, использующем асинхронность при обращении к не поточно-ориентированному коду, например, в DbContext, могут возникнуть проблемы, при которых происходит несколько асинхронных вызовов, не ожидая каждого по очереди.

т.е.

// Should be Ok...
var product = await context.Products.SingleAsync(x => x.ProductId == productId);
var customer = await context.Customers.SingleAsync(x => x.CustomerId == customerId);
var newOrder = new Order { Product = product, Customer = customer};

// Not Ok...
var productGet = context.Products.SingleAsync(x => x.ProductId == productId);
var customerGet = context.Customers.SingleAsync(x => x.CustomerId == customerId);
var newOrder = new Order { Product = await productGet, Customer = await customerGet};

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

...