2013-02-25 2 views
3

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

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

Мое предположение заключается в том, что каждый из приведенных ниже способов создает поток или использует объединенный поток. Затем блокирует этот поток до тех пор, пока не будут прочитаны данные. Сказав это и в этом контексте, есть ли какая-то заметная разница в отношении потоковой обработки, производительности и масштабируемости между методами?

В настоящее время я создаю серверное приложение. Это приложение будет иметь 1000 клиентов, создающих tcp-соединения. Эти соединения будут оставаться открытыми, часто отправляя и получая небольшие объемы данных. Я ищу использовать модель A, поскольку она проще всего реализовать и наиболее удобна в обслуживании. Будет ли в конечном итоге 1000 потоков независимо от того, какой шаблон выбран?

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

Метод A: Блокирование

Task.Factory.StartNew(ReadMessage,TaskCreationOptions.LongRunning); 
private void ReadMessage() 
{ 
    while(true) 
    { 
     TcpClient.Read(); 
    } 
} 

Метод B: Спящий

Task.Factory.StartNew(ReadMessage,TaskCreationOptions.LongRunning); 
private void ReadMessage() 
{ 
    while(true) 
    { 
     if(TcpClient.DataAvailable) 
      TcpClient.Read(); 
     else 
      Thread.Sleep(1); 
    } 
} 

Метод C: Рекурсивный Начало/Конец

private void ReadMessage() 
{ 
     stream.BeginRead(readCallBack) 
} 
private void readCallBack() 
{ 
     stream.EndRead(); 
     stream.BeginRead(readCallBack) 
} 

Метод D: Асинхронный из BCL socket.ReceiveAsync ()

private void readCallBack() 
{ 
    while(true) 
    { 
     await socket.ReceiveAsync(eventArgs); 
    } 
} 

Метод E: метод Асинхронный с блокированием Read (Использует метод D для вызова, но пользовательский метод вместо использования встроенного в exstendion сокетов от BCL)

private async Task<byte[]> ReceiveAsync() 
{ 
    return await Task.Factory.StartNew(() => TcpClient.Read()); 
} 

ответ

1

Мое предположение, что каждый из приведенные ниже методы создают поток или используют объединенный поток. Затем блокирует этот поток до тех пор, пока не будут прочитаны данные.

Совсем нет. Первые два примера блокируют потоки, но ваши два вторых примера являются асинхронными.

Асинхронные методы работают путем очередности работы ОС, а затем ждут обратного вызова, в этом случае на порту завершения ввода-вывода. Таким образом, пока чтение не ожидается, не используются нити.

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

Ваш последний пример (async) действительно так же прост, как ваш первый пример, и это будет подход, который я рекомендую, если вы не используете поток данных Rx или TPL. Когда вы выполняете связь сокетов, к тому времени, когда вы рассматриваете обработку ошибок, такую ​​как обнаружение отключенных соединений, асинхронная связь, безусловно, является способом выхода.

+0

Благодарим вас за разъяснения. Это действительно помогло.Мой последний вопрос был бы, есть ли разница между методом D и новым методом E? Может ли метод E быть таким же результативным в том, что он не блокирует потоки и вместо этого использует IOCP? –

+1

Блокирующий вызов ввода/вывода в методе «async» никогда не является хорошей идеей. Метод E блокирует вызывающий поток и не использует IOCP. Методы C и D используют IOCP и не блокируют вызывающий поток. –

+0

Исправлен метод E по вашему предложению. Я полагаю, что ответ остается в том, что он заблокирует поток и не будет использовать IOCP –