2014-10-01 5 views
0

Я не уверен, могу ли я объяснить это здесь, но позвольте мне попробовать. Код ниже - это просто показать эту идею, поскольку я просто печатаю ее здесь, не проверяя все в компиляторе.Избавьтесь от кода блокировки

У меня есть метод (скажем Method1), где я делаю две вещи. 1. Вызов метода веб-службы для выполнения действия. 2. После этого я опросу на том же веб-сервисе, чтобы дождаться появления результатов действия.

Итак, в основном что-то вроде следующего.

public class MyClass 
{ 
    Method1() 
    {  
    // call Web service method 

    // code for polling  
    } 
} 

Однако этот подход блокирует метод 1 до тех пор, пока результаты действия не станут доступны, как определено во время опроса. Я хочу изменить его так, чтобы вызывающий метод Method1 мог сразу вернуться после вызова метода веб-службы и как-то сигнализировать, как только будут доступны результаты веб-сервиса. Поэтому я думаю о наличии объекта AutoResetEvent в качестве члена класса, который я установил для состояния сигнализации во время опроса.

public class MyClass 
{ 
    public AutoResetEvent autoEvent = new AutoResetEvent(false); 
    Method1() 
    {  
    // call Web service method 

    } 

    Method2() 
    {  
    // code for polling  
    // change state of autoEvent to signaled once results are availble 

    } 

} 

При таком подходе пользователь этого API просто вызовите method1, который возвращает немедленно, и они могут просто ждать autoEvent, чтобы получить сигнал. Проблема в том, кто в этом случае будет называть Method2?

+0

Если вы собираетесь что-то ждать, вы будете блокировать, независимо от того, находится ли он в методе 1 или метод 2. Что-то блокируется, когда вы ждете события. Настоящая проблема заключается в том, что вы, похоже, не понимаете, как работает асинхронность в .NET, и просто делаете это, когда идете вперед. Я предлагаю вам начать с чтения по шаблону Begin/End Asynchronous, и если вы можете использовать .net 4.5, то прочитайте в async/await –

+0

. Я бы склонен просто оставить блок 'Method1()'. Если это проблема для вызывающего, то это то, где он должен обрабатываться, например.используя отдельный поток с любым методом синхронизации, который подходит на более высоком уровне. – HABO

+0

@Eric Спасибо за ваши комментарии. Я должен признать, что я совершенно новичок в асинхронном шаблоне. Я обязательно прочитаю ваши предложенные темы, но вы предполагаете, что я могу реализовать здесь Begin/End Asynchronous pattern. На данный момент мне придется придерживаться .NET 4.0 – BKS

ответ

1

Для асинхронного кода существует несколько различных методологий. Наиболее распространенным в .NET сегодня является использование Tasks. Для базового примера вы можете сделать что-то вроде:

Task task = Task.Run(() => DoSomething()); 
task.ContinueWith(() => DoAfterSomething()); 

Это позволяет код, чтобы продолжить обработку, пока задание выполняется в фоновом потоке. Это может показаться немногословным & clumbsy со всеми лямбдами и суб-методами, поэтому был представлен шаблон async \ await. Это выглядит примерно так:

Task<int> DoSomethingAsync() 
{ 
    // do something asynchronously.. 
} 

async Task<int> ExampleAsync() 
{ 
    int result = await DoSomethingAsync(); 
    DoAfterSomething(); 
    return 42; 
} 

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

Другая методология, которая обычно используется, - это методология APM. Это включает два метода, которые запускают асинхронный поток, а другой - для его завершения (обычно BeginX и EndX). Обычно это выглядит так:

FileStream fStream = /* etc */ 
byte[] buffer = /* etc */ 
void ReadFile(FileStream fStream) 
{ 
    var asyncResult = fStream.BeginRead(buffer, 0 , buffer.Length, new AsyncCallback(EndReadCallback), null); 
} 

void EndReadCallback(IAsyncResult result) 
{ 
    int length = fStream.EndRead(result); 
    // continue processing on buffer 
} 

Другая методика является EAP модель, которая использует события для запуска завершения. Эта модель мало используется в платформе .NET, но она находится там. Он используется что-то вроде:

WebDownload download = /* etc */ 
download.DownloadComplete += (buffer) => { /* do something with buffer */ }; 
download.Get("http://foo/img.jpg"); 

Лично я использую асинхронной \ Await для всего я создаю, но другие методы хороши, чтобы знать, в случае, если вы столкнулись с ними в устаревших компонентов. Если вам когда-либо понадобится преобразовать APM или EAP в задачу, вы можете сделать это довольно легко с помощью Task.Factory.FromAsync или используя TaskCompletionSource

Смежные вопросы