Использую ли я JoinableTaskFactory с AspNetCore?

#c# #asp.net-core #async-await

#c# #asp.net-core #асинхронное ожидание

Вопрос:

Я импортировал Microsoft.VisualStudio.Поток в .Веб-приложение Net Core. Я сделал это специально для использования AsyncLazy<T> .

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

В предупреждениях и документации четко указано, что JoinableTaskFactory следует внедрить в мою реализацию.

Мой вопрос в том, как я должен создать его JoinableTaskFactory в конфигурации моего веб-приложения .Net Core?

Это так просто, как

 public void ConfigureServices(IServiceCollection services)
{
    // ...
        services.AddSingleton(new JoinableTaskFactory());
    // ...
}
  

или это все неправильно?

Ответ №1:

Да, вы можете использовать Microsoft.VisualStudio.Threading библиотеку в ASP.NET Основные приложения. Но хотя JoinableTaskFactory в таком приложении «работает», это довольно хороший признак того, что вы делаете что-то не так.

Анализаторы, конечно, всегда уместны, и предупреждения, которые вы видели, возможно, указывали на то, что вам не следует вызывать Task.Result , Task.Wait() и т.д. Они синхронно блокируют потоки и могут серьезно снизить масштабируемость вашего веб-приложения (или любого приложения, если на то пошло). Вы должны использовать await вместо этого везде, где это возможно.

JoinableTaskFactory можно ли вмешаться, когда вы не можете использовать await, но вам все равно нужно вызвать асинхронный код. Использование JTF.Run по-прежнему будет блокировать вызывающий поток, но это будет сделано таким образом, чтобы избежать взаимоблокировок, когда у вас есть однопоточный SynchronizationContext в приложении. Я не думаю, что в ASP.NET Core есть такая вещь, так что это не проблема. JTF.Run все еще более эффективен, чем Task.Wait , поскольку он может повторно использовать исходный поток для продолжения вместо второго потока.

Если вы решите использовать JTF в своем веб-приложении, если ASP.NET Ядро не использует однопоточный SynchronizationContext тогда вы можете создать один экземпляр JTF и предоставить общий доступ ко всему приложению. Но если у него есть однопоточный SynchronizationContext , он будет по одному на веб-запрос, что означает, что вам нужно создать новый JoinableTaskContext для каждого запроса, поскольку они привязаны к одному SynchronizationContext . Вы всегда получаете свой экземпляр JTF из JoinableTaskContext экземпляра.

Комментарии:

1. для протокола, теперь я думаю, что то, что я делал, было совершенно неправильно. Я думаю, это то, что вы говорите, в более конструктивном ключе.

2. ДА. Не стесняйтесь менять принятый ответ на этот. 🙂

3. Как насчет того, чтобы вы привели рабочий пример. Это было бы полезно. В конструкторе есть параметры, которые я никогда раньше не видел. Насколько глубока эта кроличья нора?

4.Недавно нам пришлось исправить ASP.NET (Ядро?) где JoinableTaskContext было создано много, и это привело к очень большим массивам в .NET вызывает CONTEXT ненужных объектов. Вы должны создавать не более одного JoinableTaskContext запроса, и один для процесса может быть намного лучше. Пока вы создаете его, SynchronizationContext.Current == null вы можете использовать его везде. И поскольку у него есть Factory свойство, вам даже не нужно создавать JoinableTaskFactory вручную.

5. @PeetBrits ThreadHelper.JoinableTaskFactory фактически доступен только в Visual Studio, так как ThreadHelper является частью VS SDK. Для вашего собственного приложения вы можете и должны создать один JoinableTaskContext собственный объект и использовать этот объект во всем своем приложении. Вы можете поделиться им через общее свойство, как это делает VS через свой собственный ThreadHelper класс.

Ответ №2:

На этой странице документов vs-threading говорится

ThreadHelper.Свойство JoinableTaskFactory работает только для кода, выполняемого в процессе VS. Если в вашем коде заканчивается процедура (в vstest.executionengine.exe например, runner) это не сработает.

Итак, как следует из названия пакета, Microsoft.VisualStudio.Threading , он предназначен для использования с расширениями Visual Studio. Код, который вы связали для его реализации AsyncLazy, использует JoinableTaskFactory, поэтому он, вероятно, не подходит за пределами Visual Studio. Я, конечно, никогда бы не использовал его вне расширения VS, которому необходимо переключиться на поток пользовательского интерфейса.

У библиотеки AsyncExСтивена Клири есть AsyncLazy, а страница wiki ссылается на это сообщение в блоге Стивена Тоуба под названием AsyncLazy. В сообщении в блоге указывается, что отложенная семантика на самом деле мало что добавляет по сравнению с тем, что Task<T> предоставляет, хотя, поскольку фабрика значений может проделать большую работу до достижения ожидания, его образец запускает его в пуле потоков и разворачивает Task<Task<T>> .

редактировать: Как указано в комментариях, моя цитата из документов несколько вырвана из контекста. Однако библиотека vs-threading предназначена для предотвращения взаимоблокировок при использовании асинхронности с контекстом синхронизации (в первую очередь с графическим интерфейсом). ASP.NET Ядро, которое использует автор вопроса, не имеет контекста синхронизации, следовательно, ему не нужно беспокоиться о блокировке основного потока конкретно. Хотя использование библиотеки vs-threading, вероятно, не вызовет проблем, как утверждалось в моей цитате, я все же не думаю, что она подходит для чего-либо без контекста синхронизации, и есть гораздо лучшие альтернативы, такие как использование Task<T> напрямую и не требующие какой-либо реализации AsyncLazy.

Комментарии:

1. Итак, я собираюсь сделать то, что я должен был сделать в первую очередь, и использовать Nito. Вместо этого AsyncEx .

2. Я бы не согласился с этим утверждением. Хотя приведенная документация посвящена, в частности, тестированию ПРОТИВ расширений , на главной странице / readme указано, что это библиотека xplat, и мы знаем, что Visual Studio работает только в Windows (Visual Studio для Mac просто переименована в Xamarin Studio). github.com/Microsoft/vs-threading/blob/master/doc /… более понятно в инструкциях, в частности, в разделе «Одноэлементный класс со свойством JoinableTaskContext» и «Принять JoinableTaskContext в качестве аргумента конструктора».

3. Важно то, что new редактирование JoinableTaskContext происходит в основном потоке (в котором вы хотите, чтобы ваши данные были объединены), будь то поток основного метода, поток пользовательского интерфейса или какой-либо другой контекст (например, ядро aspnet или контекст расписания orleans)

4. @Tseng ты прав, я слишком поторопился скопировать вставку. Я отредактировал свой ответ, чтобы попытаться прояснить свою позицию о том, что использование библиотеки, предназначенной для избежания взаимоблокировок при использовании async с контекстом синхронизации, не является лучшим выбором при использовании фреймворка, который не использует контексты синхронизации.

5. Этот ответ неверен. Документ, на который он ссылается, относится конкретно к ThreadHelper.JoinableTaskFactory . ThreadHelper Класс определен в VS SDK, поэтому, конечно, он доступен только для расширений VS. Но JoinableTaskFactory сам по себе может использоваться и часто используется за пределами VS. Имя «VisualStudio» появляется в названии пакета и сборки, потому что команда VS создала и поддерживает его. Это не имеет никакого отношения к тому, какие приложения могут его использовать.