Каков наилучший способ получать сообщения из многих потоков в очередь и иметь отдельные потоки, обрабатывающие элементы этой очереди по одному?
Я часто использую этот шаблон, когда пытаюсь отключить действия от многих потоков.
Я использую для этого BlockingCollection, как показано в фрагменте кода ниже:
// start this task in a static constructor
Task.Factory.StartNew(() => ProcessMultiUseQueueEntries(), TaskCreationOptions.LongRunning);
private static BlockingCollection<Tuple<XClientMsgExt, BOInfo, string, BOStatus>> _q = new BlockingCollection<Tuple<XClientMsgExt, BOInfo, string, BOStatus>>();
/// <summary>
/// queued - Simple mechanism that will log the fact that this user is sending an xMsg (FROM a user)
/// </summary>
public static void LogXMsgFromUser(XClientMsgExt xMsg)
{
_q.Add(new Tuple<XClientMsgExt, BOInfo, string, BOStatus>(xMsg, null, "", BOStatus.Ignore));
}
/// <summary>
/// queued - Simple mechanism that will log the data being executed by this user
/// </summary>
public static void LogBOToUser(BOInfo boInfo)
{
_q.Add(new Tuple<XClientMsgExt, BOInfo, string, BOStatus>(null, boInfo, "", BOStatus.Ignore));
}
/// <summary>
/// queued - Simple mechanism that will log the status of the BO being executed by this user (causes the red square to flash)
/// </summary>
public static void LogBOStatus(string UserID, BOStatus status)
{
_q.Add(new Tuple<XClientMsgExt, BOInfo, string, BOStatus>(null, null, UserID, status));
}
/// <summary>
/// An endless thread that will keep checking the Queue for new entrants.
/// NOTE - no error handling since this can't fail... :) lol etc
/// </summary>
private static void ProcessMultiUseQueueEntries()
{
while (true) // eternal loop
{
Tuple<XClientMsgExt, BOInfo, string, BOStatus> tuple = _q.Take();
// Do stuff
}
}
Это работает нормально, как я и думал, пока Мастер производительности в VS2010 не начал выделять строку _q.Take() как строку с наибольшим количеством конфликтов в моем коде!
Примечание. Я также использовал стандартную ConcurrentQueue с комбинацией ManualResetEvent, и каждый раз, когда я вставляю элемент в очередь, я сигнализирую о сбросе события, позволяя рабочему потоку исследовать и обрабатывать очередь, но это также имело тот же чистый эффект выделения в . Метод WaitOne()...
Существуют ли другие способы решения этой распространенной схемы наличия множества потоков, добавляющих объекты в параллельную очередь, и иметь один поток, прокладывающий себе путь через элементы по одному и в свое время...
Спасибо!!