#c# #multithreading #asynchronous
#c# #многопоточность #асинхронный
Вопрос:
Требуется непрерывное считывание данных с аппаратного обеспечения и отправка данных на верхние уровни для дальнейшей обработки.
В настоящее время я использую синхронный механизм. т.е. Запрос -> Ожидание -> Чтение —> Отправить на обработку.
do
{
int ix = iy;
iy = 0;
if(ix<1)
{
while (((ix = ReadSst(ref sBuffer)) < 1) amp;amp; bProcessNotEnded == true)
{
if (ix < 0) // BT Error
{
eErr = CError.BUFF_KILL; //Throw error and exit
break;
}
Thread.Sleep(2);
iTimeOut = 2;
if (iTimeOut > TIMEOUT_2000)
{
eErr = CError.TIMEOUT_ERR;
objLogger.WriteLine("HW TIMED OUT");
break;
}
}
}
iBytesRead = ix;
if (iBytesRead <= 0)
{
eErr = CError.READ_ERR;
objLogger.WriteLine("READ ERROR");
break;
}
sReadMsg = sReadMsg sBuffer;
if(sReadMsg.Length >0)
iEndPos = sReadMsg.IndexOf('n',1);
else
iEndPos = -1;
if (sReadMsg.Length > 2)
{
if ((iEndPos == 0 amp;amp; sReadMsg[0] == 'n') || (iEndPos > 0 amp;amp; sReadMsg[sReadMsg.Length - 1] == 'n' amp;amp; sReadMsg[sReadMsg.Length - 2] == 'r')) //finished
{
Thread.Sleep(50); // wait a short time to be sure there that there is no further input
if (sReadMsg.Length >= 3 amp;amp; sReadMsg[sReadMsg.Length - 3] == 'a')
continue;
iy = ReadSst(ref sBuffer);
if (iy == 0)
{
bProcessNotEnded = false;
objLogger.WriteLine("bProcessNotEnded is made false, End of frame detected");
break;
}
else if (iy < 0)
{
eErr = CError.BUFF_KILL; // error
break;
}
}
}
} while (bProcessNotEnded);
Метод ReadSst — это вызов, выполняемый аппаратным обеспечением для запроса данных.
Как видно из кода, нынешняя логика, которую я выполняю в цикле и считываю до тех пор, пока флаг bProcessNotEnded не станет истинным. Как только в получаемом строковом буфере обнаруживается конец кадра, я устанавливаю флаг в false, и цикл прекращается (как и чтение с аппаратного обеспечения)
Теперь, когда мне нужно добиться некоторого параллелизма в моем коде для повышения производительности, я хочу научиться улучшать его таким образом, чтобы чтение выполнялось асинхронным способом.
Любой, кто может помочь мне в улучшении этого существующего дизайна.
Заранее спасибо
Комментарии:
1. Это слишком низкий уровень. Оберните это потоком памяти, и у вас будут операции синхронизации / асинхронности.
2. Здравствуйте, возможно, вы захотите опубликовать это в codereview.stackexchange.com слишком
Ответ №1:
Как правило, существует три распространенных шаблона для выполнения асинхронной работы в .NET:
- Модель асинхронного программирования
- Модель асинхронного программирования на основе событий
- Библиотека параллельных задач (.NET 4.0)
Для вашего явно низкоуровневого фрагмента кода я бы выбрал 1 или 3, поскольку 2 обычно используется в компонентах более высокого уровня.
Общий дизайн, к которому следует прибегнуть, заключается в выполнении вашего цикла в отдельном потоке любым из вышеперечисленных способов, а по завершении цикла уведомляет вызывающий поток о завершении операции, передавая результат (в вашем случае это должно быть содержимое sReadMsg
) соответствующим образом (зависит от того, какой способ вы выберете).
Вот краткий пример того, как легко вы могли бы это сделать, используя TPL:
private void ReadMessageAsync()
{
// Set up the task to read the message from the hardware device.
Task<string> readMessageTask = new Task<string>(ReadMessage);
// Set up the task to process the message when the message was read from the device.
readMessageTask.ContinueWith(ProcessMessage);
// Start the task asynchronously.
readMessageTask.Start();
}
private void ProcessMessage(Task<string> readMessageTask)
{
string message = readMessageTask.Resu<
// Process the message
}
private string ReadMessage()
{
string message = string.Empty;
// Retrieve the message using your loop
return message;
}
Комментарии:
1. Привет, Флориан, я ограничен .NET Framework 2.0, я не могу использовать TPL: (учащийся
Ответ №2:
Я думаю, что ваш дизайн можно было бы улучшить, используя асинхронный ввод-вывод. Мы не видели, как ReadSst
это было реализовано, но я подозреваю, что вы где-то там используете Stream
. Вместо вызова Read
(который является синхронным) вы бы использовали BeginRead
вместо этого (который является асинхронным). Это изменение приведет к другим, более значительным изменениям в дизайне кода. Я бы начал с исследования асинхронного ввода-вывода и попытался реализовать самостоятельно, а затем опубликовал последующие вопросы, если это более конкретные проблемы, с которыми мы можем помочь.
Ответ №3:
Существует компонент .net под названием Background worker, вы можете поместить обработку цикла в событие ‘DoWork’ и одновременно поддерживать отзывчивость вашего приложения.
Вот класс, который предоставляет это:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=VS.90).aspx
Также содержит хороший пример того, как его использовать.
Надеюсь, это поможет