如何在不阻止Django渠道中执行的情况下运行异步功能

问题描述

我有一个AsyncWebsocketConsumer正在运行django频道,用于基于回合的在线游戏。

需要验证与当前回合关联的玩家是否在线,如果不是,则服务器应等待5秒钟,以便玩家有机会回来,然后再更新回合并传递到下一个回合播放器。

在向连接的播放器发送新状态的函数的末尾(每次客户端向套接字发送修改状态的消息时都会调用该状态),您有以下两行:

await self.send_new_state_to_all_players(event_specifics)
await self.check_current_player_online(game_id) # routine to handle the case where current player isn't online  

方法check_current_player_online()执行此操作:

async def check_current_player_online(self,game_id):
        current_turn_player_number = await self.get_current_turn(game_id)
        if await self.is_online(await self.get_player_id_from_number(game_id,current_turn_player_number)): # if current player is online,resume normal game flow
            return

        await asyncio.sleep(5)

        if not await self.is_online(await self.get_player_id_from_number(game_id,current_turn_player_number)): # if player hasn't come back,increment turn
            await self.increment_turn(game_id)
            await self.send_new_state_to_all_players({
                'type': 'pass_turn',})

预期的行为:当不在线玩家的回合来临时,每个玩家都应收到send_new_state_to_all_players发送的新状态,并被告知 xyz 的回合(离线播放器),然后在5秒钟后,如果 xyz 尚未恢复在线状态,则套接字应在更新转弯后发送新的state消息。

实际行为:预期行为发生在每个人,但最后一个套接字发送消息的玩家是触发check_current_player_online()的玩家。当函数完成运行5秒钟后,它们将不会收到第一个新状态,并且只会从check_current_player_online()接收更新状态和第二个更新状态。

这是send_new_state_to_all_players及其调用的处理程序的实现:

async def send_new_state_to_all_players(self,event_specifics):
        game_id = self.scope['url_route']['kwargs']['game_id']
        for player in await sync_to_async(list)(Player.objects.filter(Q(game_id=game_id))):
            await self.channel_layer.group_send(
                self.game_group_name,{
                    'type': 'game_state_handler','player_id': player.pk,'event_specifics': event_specifics,}
            )

# handler
    async def game_state_handler(self,event):
        if(self.scope['session']['player_id'] != event['player_id']):
            return
        state = await self.get_game_state(self.scope['url_route']['kwargs']['game_id'],event['player_id'])
        await self.send(text_data=json.dumps({
            'type': 'new_state','state': state,'event_specifics': event['event_specifics'],}))

# function called by the handler

@database_sync_to_async
    def get_game_state(self,game_id,player_id):
        # Returns a dictionary holding the game's state
        game = Game.objects.get(pk=game_id)
        
        this_player = Player.objects.get(pk=player_id)
        this_player_cards = CardsInHand.objects.filter(player_id=player_id)
        my_cards = []
        for card in this_player_cards:
            card_str = str(card.card_number) + card.card_seed
            my_cards.append(card_str)
        
        other_players_list = []
        other_players = Player.objects.filter(Q(game_id=game_id) & ~Q(pk=player_id))
        for player in other_players:
            player_data = {
                'number': player.player_number,'is_online': player.is_online,'number_of_cards': CardsInHand.objects.filter(player_id=player).count(),'name': player.name,}
            other_players_list.append(player_data)
        state = {
            'current_turn': game.player_current_turn,'last_turn': game.player_last_turn,'current_card': game.current_card,'last_card': game.last_card,'number_of_stacked_cards': len(json.loads(game.stacked_cards)),'last_amount_played': game.last_amount_played,'won_by': game.winning_player if game.has_been_won else -1,'my_cards': my_cards,'other_players_data': other_players_list,'my_player_number': this_player.player_number,}

        return state


为什么会这样?如何使该过程畅通无阻或强制第一个功能运行到最后再移至第二个功能

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)