ОБНОВЛЕНИЕ 14 июня 2011
Быстрое обновление ... Большинство респондентов сконцентрировались на хитром методе обработки очереди сообщений, которые должны регистрироваться, однако, хотя там, безусловно, не хватает оптимизации, это, конечно, не является корнем проблемы. Мы переключили Yield на короткий сон (да, выход действительно привел к 100% CPU, когда система отключилась), однако система все еще не может идти в ногу с журналированием, даже если она не приближается к этому сну. Из того, что я вижу, отправка просто не очень эффективна. Один респондент отметил, что мы должны объединить Send () в одну отправку, и это кажется наиболее подходящим решением для основной проблемы, и именно поэтому я отметил это как ответ на первоначальный вопрос. Я, конечно, согласен с тем, что модель очереди очень ошибочна, поэтому спасибо за отзывы об этом, и я проголосовал за все ответы, которые внесли вклад в обсуждение.
Однако, это упражнение заставило нас рассмотреть , почему мы используем внешнее ведение журнала через сокет, как и мы, и хотя это вполне могло иметь смысл ранее, когда сервер журналирования выполнял много обработки поверх записей журнала ... он больше ничего не делает, и поэтому мы решили удаленно удалить весь этот модуль и перейти к подходу "напрямую к файлу" с помощью некоторой ранее существующей среды ведения журнала, это также должно полностью устранить проблему как убрать ненужные сложности в системе.
Еще раз спасибо за все отзывы.
ОРИГИНАЛЬНЫЙ ВОПРОС
В нашей системе у нас есть два компонента, важных для этой проблемы: один разработан на Visual C ++, а другой - на Java (не спрашивайте, исторические причины).
Компонент C ++ является основным сервисом и генерирует записи в журнале. Эти записи журнала отправляются через CSocket :: Send to Java logging service.
Проблема
Производительность отправки данных кажется очень низкой. Если мы ставим в очередь на стороне C ++, то эта очередь постепенно резервируется в загруженных системах.
Если я попаду на сервер журналирования Java с помощью простого приложения на C #, то смогу справиться с этим быстрее, чем когда-либо, с помощью инструмента C ++, и он будет прекрасно работать.
В мире C ++ функция, добавляющая сообщения в очередь:
void MyLogger::Log(const CString& buffer)
{
struct _timeb timebuffer;
_ftime64_s( &timebuffer );
CString message;
message.Format("%d%03d,%04d,%s\r\n", (int)timebuffer.time, (int)timebuffer.millitm, GetCurrentThreadId(), (LPCTSTR)buffer);
CString* queuedMessage = new CString(message);
sendMessageQueue.push(queuedMessage);
}
Функция запускается в отдельном потоке, который отправляет в сокет:
void MyLogger::ProcessQueue()
{
CString* queuedMessage = NULL;
while(!sendMessageQueue.try_pop(queuedMessage))
{
if (!running)
{
break;
}
Concurrency::Context::Yield();
}
if (queuedMessage == NULL)
{
return;
}
else
{
socket.Send((LPCTSTR)*queuedMessage, queuedMessage->GetLength());
delete queuedMessage;
}
}
Обратите внимание, что ProcessQueue многократно запускается самим потоком внешнего цикла, что исключает кучу бессмысленной преамбулы:
while(parent->running)
{
try
{
logger->ProcessQueue();
}
catch(...)
{
}
}
Очередь:
Concurrency::concurrent_queue<CString*> sendMessageQueue;
Таким образом, эффект, который мы наблюдаем, состоит в том, что очередь становится все больше и больше, записи журнала отправляются в сокет, но с гораздо меньшей скоростью, чем они собираются.
Это ограничение CSocket :: Send, которое делает его менее полезным для нас? Неправильное использование этого? Или целая красная сельдь и проблема в другом?
Ваш совет очень ценится.
С уважением
Мэтт Педлсден