简体   繁体   中英

Stateless Statemachine Framework and high CPU usage

I'm using the Stateless Framework to create a StateMachine. My Main Application is a ConsoleApplication which calls the DataManager class, which calls the GetData function which starts a Task which then executes the Receiver function with the state machine.

My Problem is that I get about 50% CPU usage when the StateMachine runs! When I implement a StateMachine with a simple switch statement and the same Task it runs with a 0% CPU usage! Do I have a some coding error or is that the behaivor of the Stateless Framework?

The GetData function

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;
} 

The DataManager class

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;
}

Regards Michael

Change the wait loop

     while (_machine.State != State.End)
     {
         Thread.Sleep(10); // Only check once in a while
     }

Another way to do this very efficiently without looping;

Create a ManualResetEventSlim object;

 ManualResetEventSlim mre = new ManualResetEventSlim(false);

The Wait loop changes to

 mre.Wait(); // Waits untill the mre is signaled

And when the _machine.State becomes State.End it should call

 mre.Set();

which will signal the waiter and will cause the mre.Wait() to stop waiting

Your CPU is 50% because you have 2 cores in it and your thread is consuming the 100% of one it with the while loop.

The switch statement has no wait loop so it doesnt consumes CPU.

Instead of waiting manually, just implement the Event-Based Asynchronous Pattern(EAP) :

  • Mark Receiver() as void and thus return statement should be removed.
  • Declare an event on your DataManager class like "OperationDone".
  • Fire the event with the _outputList at the last step of the steate machine.
  • Capture the event to return the value.

Now the only CPU consumption will be done by the state machine framework.

Another usefull link: How to: Wrap EAP Patterns in a Task .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM