Intereting Posts
Кодирование URL-адресов в c # и asp.net web api ASP.Net 4.5 Сортировка привязки модели по свойствам навигации c # присваивать 1 мерный массив синтаксису 2-мерного массива C # / EF и шаблон хранилища: где разместить ObjectContext в решении с несколькими репозиториями? Как предотвратить исключение в фоновом streamе от завершения приложения? Связывание столбцов DataGridView в WPF Как рассчитать разницу в годах и месяцах с учетом начала и конца Попросив исправить ошибки в программе, вы найдете более 100 экземпляров Преобразования цветовых пространств Исключение при анализе отрицательных двойных чисел в C # Изменение экрана запуска / экрана Splash Screen и изображения Xceed WPF свойствоGrid показать элемент для расширенной коллекции c # Добавление метода Remove (int index) к classу .NET Queue Как вернуть фокус из windows консоли в C #? C # Почему частичные методы используют ref, но не из?

При вызове асинхронного метода WCF на основе задачи используется порт завершения ввода-вывода или stream streamа нитей для вызова продолжения?

У меня есть следующий контракт WCF:

[ServiceContract(Namespace = "http://abc/Services/AdminService")] public interface IAdminService { [OperationContract] string GetServiceVersion(); // More methods here } 

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

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

Итак, для этой цели я придумал следующий интерфейс:

 [ServiceContract(Namespace = "http://abc/Services/AdminService")] public interface IMiniAdminService { [OperationContract(Action = "http://abc/Services/AdminService/IAdminService/GetServiceVersion", ReplyAction = "http://abc/Services/AdminService/IAdminService/GetServiceVersionResponse")] Task GetServiceVersionAsync(); } 

Это позволяет асинхронно вызывать API GetServiceVersion :

 var tmp = new ChannelFactory("AdminServiceClientEndpoint"); var channelFactory = new ChannelFactory(tmp.Endpoint.Binding, tmp.Endpoint.Address); var miniAdminService = channelFactory.CreateChannel(); return miniAdminService.GetServiceVersionAsync().ContinueWith(t => { if (t.Exception != null) { // The Admin Service seems to be unavailable } else { // The Admin Service is available } }); 

Код работает.

Мой вопрос заключается в следующем: использует ли он IOCP для вызова продолжения?

В общем, есть ли способ узнать, вызывается ли продолжение через IOCP или нет (в отладчике, если необходимо)?

PS

Вот трассировка стека моего продолжения метода async WCF:

 > *** My Code *** Line 195 C# mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromResultTask.InnerInvoke() + 0x111 bytes mscorlib.dll!System.Threading.Tasks.Task.Execute() + 0x69 bytes mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) + 0x4f bytes mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x28d bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x47 bytes mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) + 0x3b5 bytes mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) + 0x104 bytes mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x2a bytes mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x249 bytes mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x1e bytes [Native to Managed Transition] 

Теперь эта трассировка стека очень похожа на ту, которую я получаю для метода, вызванного из Task.Factory.StartNew , который действительно является Task.Factory.StartNew streamов на основе:

 > *** My Code *** Line 35 C# mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke() + 0x59 bytes mscorlib.dll!System.Threading.Tasks.Task.Execute() + 0x60 bytes mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) + 0x37 bytes mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x1a2 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x33 bytes mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) + 0x2ff bytes mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) + 0xd3 bytes mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x22 bytes mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x22e bytes mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x18 bytes [Native to Managed Transition] 

Во-первых, вам нужно добавить TaskContinuationOptions.ExecuteSynchronously , чтобы убедиться, что вызов обратного вызова вызывается в том же streamе, операция async IO была завершена:

 return miniAdminService.GetServiceVersionAsync().ContinueWith(t => { if (t.Exception != null) { // The Admin Service seems to be unavailable } else { // The Admin Service is available } }, TaskContinuationOptions.ExecuteSynchronously); 

По-видимому, API нет в .NET, чтобы определить, является ли stream streamом пула IOCP. Вы можете только указать, является ли stream streamом пула streamов ( Thread.CurrentThread.IsThreadPoolThread ), что true для streamов IOCP.

В Win32 пул streamов IOCP создается с CreateIoCompletionPort API CreateIoCompletionPort , но я не смог найти API Win32, чтобы проверить, принадлежит ли stream этому пулу.

Итак, вот немного надуманный пример, чтобы проверить эту теорию на практике, используя HtppClient в качестве тестового автомобиля. Во-первых, мы уверены, что все streamи, ThreadStatic от ThreadStatic переменную s_mark с -1 . Затем мы запускаем операцию с привязкой к IO и проверяем s_mark на stream, где s_mark операция с s_mark к IO:

 using System; using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication_22465346 { public class Program { [ThreadStatic] static volatile int s_mark; // Main public static void Main(string[] args) { const int THREADS = 50; // init the thread pool ThreadPool.SetMaxThreads( workerThreads: THREADS, completionPortThreads: THREADS); ThreadPool.SetMinThreads( workerThreads: THREADS, completionPortThreads: THREADS); // populate s_max for non-IOCP threads for (int i = 0; i < THREADS; i++) { ThreadPool.QueueUserWorkItem(_ => { s_mark = -1; Thread.Sleep(1000); }); } Thread.Sleep(2000); // non-IOCP test Task.Run(() => { // by now all non-IOCP threads have s_mark == -1 Console.WriteLine("Task.Run, s_mark: " + s_mark); Console.WriteLine("IsThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread); }).Wait(); // IOCP test var httpClient = new HttpClient(); httpClient.GetStringAsync("http://example.com").ContinueWith(t => { // all IOCP threads have s_mark == 0 Console.WriteLine("GetStringAsync.ContinueWith, s_mark: " + s_mark); Console.WriteLine("IsThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread); }, TaskContinuationOptions.ExecuteSynchronously).Wait(); Console.WriteLine("Enter to exit..."); Console.ReadLine(); } } } 

Выход:

 Task.Run, s_mark: -1
 IsThreadPoolThread: True
 GetStringAsync.ContinueWith, s_mark: 0
 IsThreadPoolThread: True
 Войдите, чтобы выйти ...

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

Хорошее чтение, связанное: «Нет темы» Стивена Клири.