2016-10-05 2 views
0

Итак, когда я просматриваю решение своего сокета в диспетчере задач, я замечаю, что приложение создает и уничтожает темы (от 9 до 10 до 15 назад до 10). Некоторые из них могут использоваться коннектором MySQL, но, похоже, вход в сервер будет создавать новый поток.Неявное или явное .NET Threading

Я использую асинхронные сокеты, чтобы принять соединение, передать его экземпляру PacketHandler, все время прослушивая одновременные соединения. Мой вопрос: как мне определить, какой код создаст новый поток? Я никогда не писал, что нужно создать поток, но, похоже, это следствие использования асинхронных сокетов. Я знаю, что вы должны быть консервативны при создании потоков (Cores * 2 = target # of threads), но это сложная задача, когда вы не знаете, какой код создаст новый поток по своей природе.

+3

Не беспокойтесь о том, что код не ваше. Он будет работать так, как он работает; вы не контролируете его. Если это действительно проблема, найдите другую стороннюю библиотеку. –

+0

Но это мой код. – Fuselight

+0

Я имею в виду код, который вы написали. Вы явно используете потоки? Я не имею в виду код, который вы используете, например, код рамки или сторонний код. –

ответ

3

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

Это, безусловно, относится к текущей реализации сокетов в MS.NET. Они регистрируют обратный вызов для асинхронного события, а поток threadpool используется на время этого обратного вызова. Если вы не выполняете операции синхронного ввода-вывода в обратном вызове, нет смысла создавать больше потоков в threadpool.

Не смотрите в диспетчере задач - смотрите в отладчик. Вполне возможно, что нити, которые вы видите, не имеют ничего общего с библиотекой, которую вы используете. В .NET существует немало потоков инфраструктуры, которые создаются и удаляются - особенно сборщик мусора. Проверьте трассировки стека на этих потоках, и вы будете знать, что они делают.

EDIT: И в этом случае, похоже, что MySQL Connector действительно не использует асинхронный ввод-вывод. Он просто притворяется синхронным вводом-выводом асинхронным с использованием многопоточности - другими словами, асинхронный API полностью бесполезен. И поскольку они используют потоки threadpool для синхронного ввода-вывода, вы получите много проблемы с этим. Либо используйте другую библиотеку, либо избегайте асинхронного API - это вредно для вас.

+0

Хорошо. Большое спасибо! Еще новичок в понимании потоков, и мне просто очень интересно, как они используются в приложениях, похожих на мои. – Fuselight

+0

@Fuselight Если вы делаете все на 100% прав, вам больше не нужно больше потоков, чем то, сколько CPU может выполнять одновременно. В большинстве приложений, как правило, больше потоков по разным причинам, хотя - простота, изоляция, взаимодействие, контроль ... Синхронный ввод-вывод несколько проще в использовании, особенно без расширенных языковых функций, таких как 'await'. Вся область многопоточного и асинхронного кода довольно сложна и не совсем тривиальна для правильного выбора - вы действительно хотите выбрать книгу на эту тему, если хотите сделать что-нибудь существенное. – Luaan

+0

@ Luaan OP спрашивает о MySQL Connector, который подделывает операции async с 'Task.Run'. [Этот альтернативный проект] (https://github.com/bgrainger/MySqlConnector) предлагает настоящие асинхронные операции * и * работает на .NET Core, проверен на Ubuntu –

2

К сожалению, MySQL Connector не предлагает истинных асинхронных методов. Его Begin/End методы подделкой асинхронное выполнение по wrapping the synchronous version в теме:

public IAsyncResult BeginExecuteReader(CommandBehavior behavior) 

{ 

    if (caller != null) 

    Throw(new MySqlException(Resources.UnableToStartSecondAsyncOp)); 



    caller = new AsyncDelegate(AsyncExecuteWrapper); 

    asyncResult = caller.BeginInvoke(1, behavior, null, null); 

    return asyncResult; 

} 

AsyncExecuteWrapper, где находится:

internal object AsyncExecuteWrapper(int type, CommandBehavior behavior) 

{ 

    thrownException = null; 

    try 

    { 

    if (type == 1) 

     return ExecuteReader(behavior); 

    return ExecuteNonQuery(); 

    } 

    catch (Exception ex) 

    { 

    thrownException = ex; 

    } 

    return null; 

} 

В результате, они тратят впустую поток ожидает ответа. Исправлена ​​ошибка была подана три года назад but never got a real answer

Вот почему эта альтернатива MySQLConnector был создан проект, который обеспечивает истинные асинхронные операции, а также поддержку .NET Core, например this method

internal async Task<int> ExecuteNonQueryAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) 
    { 
     using (var reader = (MySqlDataReader) await ExecuteReaderAsync(CommandBehavior.Default, ioBehavior, cancellationToken).ConfigureAwait(false)) 
     { 
      do 
      { 
       while (await reader.ReadAsync(ioBehavior, cancellationToken).ConfigureAwait(false)) 
       { 
       } 
      } while (await reader.NextResultAsync(ioBehavior, cancellationToken).ConfigureAwait(false)); 
      return reader.RecordsAffected; 
     } 
    } 

Вы увидите, что ReadAsync также надлежащий асинхронный метод

Разница значительна, особенно в веб-приложениях, так как она позволяет использовать экземпляр VM меньшего размера для сервера того же трафика. Или же виртуальная машина может увеличить трафик сервера. В любом случае разница в ценах реальна.

Это происходит потому, что асинхронные сетевые операции фактически выгружаются на драйвер или хост. Нить из пула потоков ввода-вывода используется только тогда, когда сетевой драйвер передает ответ на приложение. В случае паравиртуализации разгрузка может пройти весь путь до хоста.

Поддельные синхронные операции с другой стороны блока и могут даже привести к оживленному оживлению. Это связано с тем, что примитивы синхронизации предназначены для использования ... Синхронизация доступа к общим ресурсам. Приостановка потока расходов, поэтому ожидание на примитиве сначала начинается с Spinlock и только приостанавливает поток через определенное время.

Вот почему веб-приложения, которые не принимают во внимание асинхронность может в конечном итоге сжигание много CPU во время ожидания для удаленных ответов

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