Пример #1
0
    def run(self,
            _id: int,
            verbose: bool = False,
            timeout: int = 60000,
            n_games: int = 100):
        # hostname = f"{socket.gethostname()}_{time.ctime().replace(' ', '-')}"
        hostname = f"{socket.gethostname()}_{_id}_{time.time()}"
        address = f"tcp://{self.args.attach}:{self.args.frontend_port}"
        context = zmq.Context()
        error_sock = context.socket(zmq.REQ)
        error_sock.connect(address)

        while True:
            try:
                # alive_event:
                # 게임이 인스턴스 재시작 없이 재시작 할 때마다 set
                # 게임이 정상적으로 재시작하고 있다는 의미
                alive_event = mp.Event()
                # req_kill_event:
                # 게임 프로세스 내부에서 외부에 재시작을 요청할 때 set
                # n_games 만큼 게임을 플레이 한 뒤에 set해서
                # 게임 프로세스 내부에 문제로 인해 프로세스 종료가 안되더라도,
                # 외부에서 강제로 종료할 수 있도록 event 전달
                req_kill_event = mp.Event()
                #
                exc_queue = mp.Queue()

                def play_game(hostname, address, n_games, alive_event,
                              req_kill_event, exc_queue):
                    # n_games:
                    # 게임 인스턴스를 한번 실행해서 연속으로 몇 번이나 게임을 실행할 것인가?
                    # - 너무 작으면, 게임 인스턴스를 자주 재시작해야하기 때문에 속도가 느려짐
                    # - 너무 크면, 예외 상황이 발생할 가능성이 높음

                    # sync_event:
                    # host (게임 서버)와 join (클라이언트) 사이의 동기를 맞추기 위해 사용
                    # host가 learner에게 전달받은 대로 게임 세팅 설정한 뒤에 set을 해서,
                    # join이 다음 단계를 진행할 수 있도록 함
                    sync_event = asyncio.Event()
                    portconfig = Portconfig()

                    context = zmq.Context()
                    sock = context.socket(zmq.REQ)
                    sock.RCVTIMEO = timeout  # zmq 시간제한 설정ㄴ
                    sock.connect(address)

                    # task_dict & players:
                    # 게임 세팅 관련변수, # host와 join이 동일한 reference를 가지고 있어야 함
                    task_dict = dict(step_interval=self.args.step_interval)
                    players = [None, None]

                    asyncio.get_event_loop().run_until_complete(
                        asyncio.gather(
                            Actor._host_game(hostname,
                                             sock,
                                             task_dict,
                                             players,
                                             sync_event,
                                             alive_event,
                                             req_kill_event,
                                             exc_queue,
                                             n_games=n_games,
                                             realtime=False,
                                             portconfig=portconfig),
                            Actor._join_game(task_dict,
                                             players,
                                             sync_event,
                                             alive_event,
                                             req_kill_event,
                                             exc_queue,
                                             n_games=n_games,
                                             realtime=False,
                                             portconfig=portconfig)))

                if self.args.game_timeout < 0:
                    # 테스트 용:
                    # play_game 기능 테스트할 때, 최대 게임시간을 음수로 설정하면,
                    # play_game 함수 직접 실행
                    play_game(hostname, address, n_games, alive_event,
                              req_kill_event, exc_queue)

                else:
                    # 일반적인 상황에서는 play_game을 자식 프로세스로 실행
                    # 자식 프로세스 내부에서 종료를 요청(req_kill_event)하거나,
                    # 현재 프로세스에서 제한시간마다 게임이 새로 시작하는지 검사해서,
                    # 게임이 새로 시작하지 않으면(alive_event), 자식프로세스 재시작
                    game_play_proc = mp.Process(
                        target=play_game,
                        args=(hostname, address, n_games, alive_event,
                              req_kill_event, exc_queue),
                        daemon=False,
                    )
                    game_play_proc.start()

                    running = True
                    checkpoint = time.monotonic()
                    while running:
                        # 게임 프로세스(자식 프로세스)가 정상적으로 작동 중인지 확인
                        if req_kill_event.is_set():
                            # 게임 프로세스에서 종료 요청
                            running = False

                        if time.monotonic(
                        ) - checkpoint > self.args.game_timeout:
                            if alive_event.is_set():
                                # 제한 시간 이전에 게임 프로세스 내부에서 게임 재시작 확인
                                checkpoint = time.monotonic()
                                alive_event.clear()
                            else:
                                running = False

                        while exc_queue.qsize() > 0:
                            # 자식 프로세스에서 발행한 에러 메시지를 Learner에 전달
                            self.log_exception(hostname, error_sock,
                                               exc_queue.get())

                        time.sleep(1)

                    # 게임 프로세스 종료 시도 - sig.TERM
                    if game_play_proc.is_alive():
                        for _ in range(3):
                            game_play_proc.terminate()
                            time.sleep(0.5)
                            if not game_play_proc.is_alive():
                                break

                    # 게임 프로세스 종료 시도 - sig.KILL
                    if game_play_proc.is_alive():
                        game_play_proc.kill()
                        game_play_proc.close()

                    # 게임 프로세스 종료 시도 - psutil
                    if game_play_proc.is_alive():
                        kill_children_processes(game_play_proc.pid,
                                                including_parent=True)

            except Exception as exc:
                import traceback
                traceback.print_exc()
                self.log_exception(hostname, error_sock,
                                   traceback.format_exc())
                if self.args.halt_at_exception:
                    # 테스트용: 예외가 발생했을 때 멈춰 있도록 하기 위한 용도
                    embed()

                try:
                    kill_children_processes(including_parent=False)
                except OSError:
                    # 테스트용: 예외가 발생했을 때 멈춰 있도록 하기 위한 용도
                    # 매우 드물게 OSError가 발생할 수 있는데, 원인은 불확실 함
                    traceback.print_exc()
                    embed()
                    pass
Пример #2
0
                        cprint(f'[FUNC. UPDATE] {new_task}', 'yellow')
                        self.tasks[i] = new_task


if __name__ == '__main__':

    mp.freeze_support()  # for Windows support

    from .envs import Actor, Environment

    args = parse_arguments()

    # TODO: numpy seed
    # TODO: torch seed

    if args.attach is None:
        # os.system("kill -9 $(ps ax | grep SC2_x64 | fgrep -v grep | awk '{ print $1 }')")
        Trainer(args).run()
    else:
        if args.n_actors <= 1:
            Actor(args).run(0)
        else:
            actors = [Actor(args) for _ in range(args.n_actors)]
            ps = [
                mp.Process(target=actor.run, args=(i, ), daemon=False)
                for i, actor in enumerate(actors)
            ]
            [p.start() for p in ps]
            [p.join() for p in ps]
        kill_children_processes(including_parent=False)
Пример #3
0
    def run(self, _id: int, verbose: bool=False, timeout: int=60000, n_games: int=100):
        # hostname = f"{socket.gethostname()}_{time.ctime().replace(' ', '-')}"
        hostname = f"{socket.gethostname()}_{_id}_{time.time()}"
        address = f"tcp://{self.args.attach}:{self.args.frontend_port}"
        context = zmq.Context()
        error_sock = context.socket(zmq.REQ)
        error_sock.connect(address)

        while True:
            try: 
                # alive_event:
                # 게임이 인스턴스 재시작 없이 재시작 할 때마다 set
                # 게임이 정상적으로 재시작하고 있다는 의미
                alive_event = mp.Event()
                # req_kill_event:
                # 게임 프로세스 내부에서 외부에 재시작을 요청할 때 set
                # n_games 만큼 게임을 플레이 한 뒤에 set해서 
                # 게임 프로세스 내부에 문제로 인해 프로세스 종료가 안되더라도, 
                # 외부에서 강제로 종료할 수 있도록 event 전달
                req_kill_event = mp.Event()
                # 
                exc_queue = mp.Queue()

                ##play_game이 정의되어 있던 자리

                if self.args.game_timeout < 0:
                    # 테스트 용:
                    # play_game 기능 테스트할 때, 최대 게임시간을 음수로 설정하면,
                    # play_game 함수 직접 실행
                    ## args 인자에 timeout과 self 추가
                    play_game(hostname, address, n_games, alive_event, req_kill_event, exc_queue, timeout, self)

                else:
                    # 일반적인 상황에서는 play_game을 자식 프로세스로 실행
                    # 자식 프로세스 내부에서 종료를 요청(req_kill_event)하거나,
                    # 현재 프로세스에서 제한시간마다 게임이 새로 시작하는지 검사해서,
                    # 게임이 새로 시작하지 않으면(alive_event), 자식프로세스 재시작
                    ## args 인자에 timeout과 self 추가
                    game_play_proc = mp.Process(
                        target=play_game, 
                        args=(hostname, address, n_games, alive_event, req_kill_event, exc_queue, timeout, self),
                        daemon=False,
                    )
                    game_play_proc.start()
                    
                    running = True
                    checkpoint = time.monotonic()
                    while running:
                        # 게임 프로세스(자식 프로세스)가 정상적으로 작동 중인지 확인
                        if req_kill_event.is_set():
                            # 게임 프로세스에서 종료 요청
                            running = False

                        if time.monotonic() - checkpoint > self.args.game_timeout:
                            if alive_event.is_set():
                                # 제한 시간 이전에 게임 프로세스 내부에서 게임 재시작 확인
                                checkpoint = time.monotonic()
                                alive_event.clear()
                            else:
                                running = False

                        while exc_queue.qsize() > 0:
                            # 자식 프로세스에서 발행한 에러 메시지를 Learner에 전달
                            self.log_exception(hostname, error_sock, exc_queue.get())

                        time.sleep(1)

                    # 게임 프로세스 종료 시도 - sig.TERM                    
                    if game_play_proc.is_alive():
                        for _ in range(3):
                            game_play_proc.terminate()
                            time.sleep(0.5)
                            if not game_play_proc.is_alive():
                                break
                    
                    # 게임 프로세스 종료 시도 - sig.KILL
                    if game_play_proc.is_alive():
                        game_play_proc.kill()
                        game_play_proc.close()    

                    # 게임 프로세스 종료 시도 - psutil
                    if game_play_proc.is_alive():  
                        kill_children_processes(game_play_proc.pid, including_parent=True)                

            except Exception as exc:
                import traceback
                traceback.print_exc()
                self.log_exception(hostname, error_sock, traceback.format_exc())
                if self.args.halt_at_exception:
                    # 테스트용: 예외가 발생했을 때 멈춰 있도록 하기 위한 용도
                    embed()

                try:
                    kill_children_processes(including_parent=False)
                except OSError:
                    # 테스트용: 예외가 발생했을 때 멈춰 있도록 하기 위한 용도
                    # 매우 드물게 OSError가 발생할 수 있는데, 원인은 불확실 함
                    traceback.print_exc()
                    embed()
                    pass