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 в задачу.

Другие вопросы по тегам