Почему этот MVC метод не работает параллельно? - PullRequest
0 голосов
/ 24 марта 2020

Фон

У меня есть приложение MVC 5, и я хотел проверить, выполняются ли запросы параллельно. Для этого я воспользовался приведенным ниже кодом и открыл несколько страниц, делающих один и тот же запрос.

Код

Ниже приведен сравнительно простой метод, в котором я хотел провести параллель nature.

public async Task<ActionResult> Login(string returnUrl, string message = "")
{
    var rng = new Random();

    var wait = rng.Next(3, 10);

    var threadGuid = Guid.NewGuid();
    DebugHelper.WriteToDebugLog($"Thread {threadGuid} about to wait {wait} seconds");
    await Task.Delay(wait * 1000);
    DebugHelper.WriteToDebugLog($"Thread {threadGuid} finished");

    return View();
}

Класс DebugHelper используется только для безопасной записи в файл.

public static class DebugHelper
{
    private static readonly object WriteLock = new object();

    public static void WriteToDebugLog(string message, string path = "C:\\Temp\\Log.txt")
    {
        lock (WriteLock)
        {
            File.AppendAllLines(path, new string[] { "", GetDateString(), message });
        }
    }
}

Вывод

Я постоянно получаю вывод такого типа, который предполагает, что потоки блокируют друг друга.

2020-03-24T13:43:43.1431913Z
Thread 6e42a6c5-d3cb-4541-b8aa-34b290952973 about to wait 7 seconds

2020-03-24T13:43:50.1564077Z
Thread 6e42a6c5-d3cb-4541-b8aa-34b290952973 finished

2020-03-24T13:43:50.1853278Z
Thread 90923f55-befd-4224-bdd8-b67f787839fc about to wait 4 seconds

2020-03-24T13:43:54.1943271Z
Thread 90923f55-befd-4224-bdd8-b67f787839fc finished

2020-03-24T13:43:54.2312257Z
Thread fa2d8d30-b762-4262-b188-0b34da5f4f04 about to wait 3 seconds

2020-03-24T13:43:57.2370556Z
Thread fa2d8d30-b762-4262-b188-0b34da5f4f04 finished

2020-03-24T13:43:57.2679690Z
Thread 37311a0e-d19e-4563-b92a-5e5e3def379a about to wait 8 seconds

2020-03-24T13:44:05.2812367Z
Thread 37311a0e-d19e-4563-b92a-5e5e3def379a finished

Вопрос

Почему это происходит?

У меня сложилось впечатление, что любое приложение ASP. NET было многопоточным с самого начала, поэтому даже в ситуации, когда у меня нет установки async/await, я думал, что она будет запускать эти потоки одновременно.

Обновление

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

var targetTime = DateTime.UtcNow + TimeSpan.FromSeconds(5);
while(DateTime.UtcNow < targetTime)
{
    DebugHelper.WriteToDebugLog($"Thread {threadGuid} with ID {threadId} doing stuff");
    await Task.Delay(1000);
}

Ответы [ 2 ]

0 голосов
/ 24 марта 2020

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

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

к контроллеру.

Кроме того, ожидание по умолчанию продолжится в том же потоке, который начал ожидание. Попробуйте использовать configureAwait (false), чтобы позволить ему быть гибким в потоках, которые он использует.

await Task.Delay(wait * 1000).ConfigureAwait(false);
0 голосов
/ 24 марта 2020

Это просто сводится к тому факту, что ведение журнала отладки с WriteLock и синхронным File.AppendAllLines вызывает блокировку синхронизации для всех асинхронных функций, которые ее вызывают.

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

Шаблон продукта / потребителя, семафоры, события, использование API-интерфейсов асинхронного доступа к файлам - все это приходит на ум.

...