Как обеспечить изменение потока при выполнении async/await?

При выполнении awaitTask может или не может выполняться в том же потоке. Обычно нам просто нужно учитывать этот факт при проектировании. Но я хотел бы сделать тест специально для сценария смены потока — как мне убедиться, что остальная часть асинхронного метода (после ожидания) выполняется в другом потоке?

Возможное решение:

    [Test]
    public void TestForThreadChange()
    {
        int threadIdBefore, threadIdAfter = 0;

        async Task AsyncFunction()
        {
            Console.WriteLine($"before - {threadIdBefore = Thread.CurrentThread.ManagedThreadId}");
            await Task.Yield();
            Console.WriteLine($"after - {threadIdAfter = Thread.CurrentThread.ManagedThreadId}");
        }

        AsyncFunction().Wait();

        Assert.That(threadIdBefore, Is.Not.EqualTo(threadIdAfter));
    }

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

Zakk Diaz 24.05.2019 19:56
«нам просто нужно принять во внимание этот факт при проектировании» -- совсем нет. Ваш код вообще не должен зависеть от того, где выполняется продолжение. Действительно, поскольку номинально асинхронная задача может выполняться синхронно (например, асинхронное чтение, когда данные уже буферизованы и готовы к возврату), вы никогда не можете вообще гарантировать, что продолжение выполняется в другом потоке, да и не хотели бы этого.
Peter Duniho 27.05.2019 01:55

@PeterDuniho, да, именно это я и имел в виду ... вам просто нужно знать, что изменение потока может произойти, и разработать код, который не зависит от того, работает ли он в том же или другом потоке.

mivra 27.05.2019 02:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
171
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Ответ принят как подходящий

how do I ensure the rest of the async method (after await) is run on a different thread?

Во-первых, убедитесь, что вы вызвали тестируемый метод из контекста пула потоков. Некоторые среды модульного тестирования предоставляют однопоточный контекст. Если это так, вам нужно обернуть код тестирования в await Task.Run(() => ...).

Затем смоделируйте ожидаемый метод и убедитесь, что он выполняет await Task.Yield(); это гарантирует, что await в тестируемом методе получит незавершенную задачу, что приведет к ее возобновлению в потоке пула потоков.

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

Спасибо, @stephen-cleary. Именно туда я и направлялся. Я просто не был уверен в блокирующей части. Разве теоретически не возможно, что даже если асинхронный метод возвращает незавершенную задачу, он все равно должен быть выполнен до того, как тестовый метод достигнет Wait()? Я добавил возможное решение к ответу.

mivra 26.05.2019 00:16

@mivra: Да, он может завершиться до того, как его ожидают. Ваше решение не гарантирует возобновления работы метода в другом потоке; Я бы рекомендовал заблокировать задачу вместо использования await, чтобы гарантировать, что она возобновится в другом потоке.

Stephen Cleary 26.05.2019 01:39

о, тогда просто используйте Wait() для асинхронной функции. Я правильно понял?

mivra 27.05.2019 01:35

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

Stephen Cleary 27.05.2019 03:35

Другие вопросы по теме