Statelessine Framework и состояние процессора
Я использую Stateless Framework для создания StateMachine. Мое основное приложение - это приложение ConsoleApplication, которое вызывает DataManager
класс, который вызывает GetData
функция, которая запускает Task
который затем выполняет Receiver
работать с конечным автоматом.
Моя проблема в том, что при запуске StateMachine я получаю около 50% загрузки ЦП! Когда я реализую StateMachine с простым оператором switch и той же задачей, он запускается с 0% загрузкой процессора! У меня есть какая-то ошибка кодирования или это поведение Stateless Framework?
Функция GetData
public List<Byte[]> GetData()
{
List<Byte> rawData = new List<Byte[]>();
ReceiveTask = Task.Factory.StartNew<List<Byte[]>>(() => Receiver());
//Wait until the Task is complete
ReceiveTask.Wait();
//return temp;
rawData = ReceiveTask.Result;
return rawData;
}
Класс DataManager
public partial class DataManager
{
int _expectedBlocks;
Byte[] _currentMessage = null;
Byte[] _firstMessage = null;
int _currentBlockNumber = 0;
enum State { Idle, Start, Next, Check, End }
enum Trigger { DataOK, DataRequest, ReceivingFirstBlock, ReceivingNextBlock, LastPacketReceived, WaitForNext }
Dictionary<int, Byte[]> _receivedData;
List<Byte[]> _outputList;
StateMachine<State, Trigger> _machine;
private List<Byte[]> Receiver()
{
_currentMode = Mode.Receive;
m_source.MessageReceivedEvent +=new EventHandler<WSANMessageResponseEventArgs>(m_source_MessageReceivedEvent);
m_source.StartConnection();
_machine = new StateMachine<State, Trigger>(State.Idle);
_receivedData = new Dictionary<int, byte[]>();
_outputList = new List<byte[]>();
//Config StateMachine
_machine.Configure(State.Idle)
.OnEntry(() => OnIdle())
.OnExit(() => ExitIdle())
.Permit(Trigger.ReceivingFirstBlock, State.Start);
_machine.Configure(State.Start)
.OnEntry(() => OnStart())
.Permit(Trigger.ReceivingNextBlock, State.Next);
_machine.Configure(State.Next)
.OnEntry(() => OnNext())
.Permit(Trigger.WaitForNext, State.Start)
.Permit(Trigger.LastPacketReceived, State.Check);
_machine.Configure(State.Check)
.OnEntry(() => OnCheck())
.Permit(Trigger.DataOK, State.End)
.Permit(Trigger.DataRequest, State.Idle);
_machine.Configure(State.End)
.OnEntry(() => OnEnd());
while (_machine.State != State.End)
{
}
_currentMode = Mode.Idle;
return _outputList;
}
С уважением Майкл
2 ответа
Изменить цикл ожидания
while (_machine.State != State.End)
{
Thread.Sleep(10); // Only check once in a while
}
Еще один способ сделать это очень эффективно без зацикливания;
Создать объект ManualResetEventSlim;
ManualResetEventSlim mre = new ManualResetEventSlim(false);
Цикл ожидания меняется на
mre.Wait(); // Waits untill the mre is signaled
И когда _machine.State становится State.End, он должен вызвать
mre.Set();
который подаст сигнал официанту и заставит mre.Wait() перестать ждать
Ваш ЦП на 50%, потому что у вас есть 2 ядра, а ваш поток потребляет 100% от него с циклом while.
Оператор switch не имеет цикла ожидания, поэтому он не потребляет процессор.
Вместо того чтобы ждать вручную, просто внедрите асинхронный шаблон на основе событий (EAP):
- Пометьте Receiver() как void и, следовательно, оператор return должен быть удален.
- Объявите событие в вашем классе DataManager, например "OperationDone".
- Запустите событие с _outputList на последнем шаге steate-машины.
- Захватите событие, чтобы вернуть значение.
Теперь единственное потребление ресурсов процессора будет выполняться платформой конечного автомата.
Еще одна полезная ссылка: Как: Обернуть шаблоны EAP в задачу.