Asp.Net Core 2.1 await не дает контроль вызывающей стороне при втором запуске - PullRequest
0 голосов
/ 12 ноября 2018

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

например. -

Я вставляю 100 строк в таблицу в базе данных в цикле. Функция, которая делает это, является асинхронной функцией. Кажется, он не поддается контролю вызывающей стороне, когда его ждет. Код ниже -

[HttpGet]
[Route("/api/logtest")]
public async Task<JObject> logTestAsync()
{
    JObject retval = new JObject();
    DateTime dt1 = DateTime.Now;

    Task t = BulkLogInsertAsync();


    DateTime dt2 = DateTime.Now;
    retval["Exec_Time"] = dt2.Subtract(dt1).TotalMilliseconds;

    await t;

    DateTime dt3 = DateTime.Now;
    retval["Await_Time"] = dt3.Subtract(dt2).TotalMilliseconds;
    return retval;
}

private async Task BulkLogInsertAsync()
{
    List<Task<int>> allTasks = new List<Task<int>>();
    for (int i = 0; i<100;i++)
    {
         allTasks.Add(LogInsertAsync("insert into logs values (getdate() , 'custom' , 'sample message. ', 'Log.bills', 'callsite1', '', '', '')"));
        //allTasks.Add(LogInsertAsync("WAITFOR DELAY '00:00:02';"));
    }
    await Task.WhenAll(allTasks.ToArray()).ConfigureAwait(false);
}
private async Task<int> LogInsertAsync(string cmd)
{
    int res = 0;
    using (SqlConnection hookup = new SqlConnection(@"[mycnstr]"))
    {
        Task connectionOpeningTask = hookup.OpenAsync();
        using (SqlCommand sqlcmd = new SqlCommand(cmd, hookup))
        {
            await connectionOpeningTask.ConfigureAwait(false);
            res = await sqlcmd.ExecuteNonQueryAsync().ConfigureAwait(false);
        }
        hookup.Close();
    }
    return res;
}

Когда я вызываю API / api / logtest в первый раз, мне кажется, что я получаю желаемые результаты с exec_time, намного меньшим, чем await_time (0,2 с против 4 с)

Однако, начиная со второго запуска, я получаю await_time намного меньше, чем exec_time (4 с против 0,2 с), что заставляет меня поверить, что код работает синхронно.

Кроме того, тот же код в консольном приложении, использующем .net framework 4.6.1, непрерывно дает желаемые результаты. и нет я не перезапускаю консольное приложение. Запустил BulkLogInsertAsync в цикле do while :-)

Может кто-нибудь сказать мне, где я иду не так?

1 Ответ

0 голосов
/ 12 ноября 2018

Давайте сделаем пару вещей прямо:

  1. Нити - это не магические ресурсы, которые просто лежат там, работая для работы
  2. Чем больше у вас потоков, тем больше ресурсов вам потребуется для управления ими
  3. Асинхронность, хотя и очень полезная, не легкая вещь

Хорошо, во-первых, ваше приложение запускается с предопределенным количеством потоков w8ing (обычно количество ядер * 2, если я правильно помню, можно найти чертову статью msdn). Если вы запрашиваете темы и используете их по этому пределу, вы получаете их мгновенно, в противном случае вам потребуется w8 500 мс (не могу найти статью)

Во-вторых, асинхронность не параллельна !

В-третьих, в вашем коде, когда вы используете await, он ждет! Итак, я рекомендую вам рефакторировать ожидание на OpenAsync, соединяясь с ContinueWith и использовать его только один раз в вашем коде, потому что, как сейчас, ваши using мешают async работать должным образом. .. вам придется самостоятельно управлять соединениями и утилизацией, если вы хотите, чтобы код выполнялся асинхронно

Edit1:

Существует 2 типа потоков: потоки ввода-вывода и рабочие потоки. В вашем коде вам нужны потоки ввода-вывода на w8 для базы данных ... если вам нужно больше контекста, вы можете начать здесь

...