Python F.S.M. 2nd

https://github.com/pytransitions/transitions

앞서의 상태머신 코드 라이브러리는 실행할 때에 시간을 많이 소모하고 ,

상태머신 이동 관계가 복잡해질 경우 디버깅이 어려워지는 단점이 있다.

그래서 다른 코드를 테스트 해 보기로 한다.

위의 페이지를 참조하여 실행

from transitions import Machine
import random

class NarcolepticSuperhero(object):

    # Define some states. Most of the time, narcoleptic superheroes are just like
    # everyone else. Except for...
    states = ['asleep', 'hanging out', 'hungry', 'sweaty', 'saving the world']

    def __init__(self, name):

        # No anonymous superheroes on my watch! Every narcoleptic superhero gets
        # a name. Any name at all. SleepyMan. SlumberGirl. You get the idea.
        self.name = name

        # What have we accomplished today?
        self.kittens_rescued = 0

        # Initialize the state machine
        self.machine = Machine(model=self, states=NarcolepticSuperhero.states, initial='asleep')

        # Add some transitions. We could also define these using a static list of
        # dictionaries, as we did with states above, and then pass the list to
        # the Machine initializer as the transitions= argument.

        # At some point, every superhero must rise and shine.
        self.machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out')

        # Superheroes need to keep in shape.
        self.machine.add_transition('work_out', 'hanging out', 'hungry')

        # Those calories won't replenish themselves!
        self.machine.add_transition('eat', 'hungry', 'hanging out')

        # Superheroes are always on call. ALWAYS. But they're not always
        # dressed in work-appropriate clothing.
        self.machine.add_transition('distress_call', '*', 'saving the world',
                         before='change_into_super_secret_costume')

        # When they get off work, they're all sweaty and disgusting. But before
        # they do anything else, they have to meticulously log their latest
        # escapades. Because the legal department says so.
        self.machine.add_transition('complete_mission', 'saving the world', 'sweaty',
                         after='update_journal')

        # Sweat is a disorder that can be remedied with water.
        # Unless you've had a particularly long day, in which case... bed time!
        self.machine.add_transition('clean_up', 'sweaty', 'asleep', conditions=['is_exhausted'])
        self.machine.add_transition('clean_up', 'sweaty', 'hanging out')

        # Our NarcolepticSuperhero can fall asleep at pretty much any time.
        self.machine.add_transition('nap', '*', 'asleep')

    def update_journal(self):
        """ Dear Diary, today I saved Mr. Whiskers. Again. """
        self.kittens_rescued += 1

    @property
    def is_exhausted(self):
        """ Basically a coin toss. """
        return random.random() < 0.5

    def change_into_super_secret_costume(self):
        print("Beauty, eh?")

F.S.M.은 샘플 코드이다.

>>> batman = NarcolepticSuperhero("Batman")
>>> batman.state
'asleep'

>>> batman.wake_up()
>>> batman.state
'hanging out'

>>> batman.nap()
>>> batman.state
'asleep'

>>> batman.clean_up()
MachineError: "Can't trigger event clean_up from state asleep!"

>>> batman.wake_up()
>>> batman.work_out()
>>> batman.state
'hungry'

# Batman still hasn't done anything useful...
>>> batman.kittens_rescued
0

# We now take you live to the scene of a horrific kitten entreement...
>>> batman.distress_call()
'Beauty, eh?'
>>> batman.state
'saving the world'

# Back to the crib.
>>> batman.complete_mission()
>>> batman.state
'sweaty'

>>> batman.clean_up()
>>> batman.state
'asleep'   # Too tired to shower!

# Another productive day, Alfred.
>>> batman.kittens_rescued
1

상태도는 아래와 같다.

설명을 잘 하기 위해서 몇가지 종류의 상태를 두었다.

아무때나 갑자기 이동할 수 있는 상태로 asleep을 두었다.

그리고, 특정 조건에서 이동 가능한 상태를 확인 하기 위해서 clean_up 으로 이동하는 조건을 만들었다.

states = ['asleep', 'hanging out', 'hungry', 'sweaty', 'saving the world']

상태는 위와 같이 states라는 list로 정의 된다.

        self.machine = Machine(model=self, states=NarcolepticSuperhero.states, initial='asleep')

초기화 코드는 위와 같다.

인자는

  1. 모델 파라미터
  2. states : 상태
  3. 초기치

등을 준다.

 self.machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out')

상태 이동은 위와 같다.

trigger는 이 함수가 호출되면 상태가 이동하는 것이고

source와 dest는 각각 상태의 시작과 끝이다.

>>> batman.wake_up()
>>> batman.state
'hanging out'

위와 같이 wake_up을 호출하면 상태가 이동하게 된다.

>>> batman.clean_up()
>>> batman.state
'asleep'   # Too tired to shower!

같은 방법으로 이동하게 된다.

        # Our NarcolepticSuperhero can fall asleep at pretty much any time.
        self.machine.add_transition('nap', '*', 'asleep')

아무때나 nap을 호출하면 asleep으로 이동하게 된다.

>>> batman.nap()
>>> batman.state
'asleep'

결과…

같은 코드를 F.S.M을 변경해서 수행하면 이전에는 0.0003~5초에 한 턴씩 진행했는데

이 F.S.M.으로 하면 0.00007~0.00015 정도로 걸린다.

따라서 약 25% ~ 33%로 시간을 줄일 수 있다.

F.S.M.은 이 모듈로 하기로 한다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

WordPress.com 제공.

위로 ↑

%d 블로거가 이것을 좋아합니다: