python人物移动演示线程的使用

import time
import threading
import random
import sys

event = threading.Event()  # 创建事件线程开关
command_list = ['all', [0, 0, 0]]  # 创建动作指令,用于主线程随机改变动作指令时,第1个值表示影响的人物,第2个值是列表,设置三个坐标方向的动作开关,与人物的移动状态相对应
lock = threading.RLock()  # 创建可重用锁,用于当改变共用资源时,锁住线程

'''本例子用于演示在主线程中控制5个人物(子线程)的移动'''


class Actor:  # 创建人物类
    ids = {}  # 静态字典用于存储所有已经创建的人物
    pz_max = [100000, 100000, 100000]

    def __init__(self, user_id, user_name, password):
        if user_id in Actor.ids:  # 如果id已经被创建过的人物所使用,则抛出异常,id键不能重复
            raise Exception('id已被使用')
        self.id = user_id
        self.name = user_name
        self.pw = password
        self.age = None
        self.sex = None
        self.trans_state = [0, 0, 0]  # 人物的移动状态,分别对x,y,z三个轴坐标设置了0,1,2状态码,分别表示:停止,正向,反向
        self.step = 1  # 初始的移动步长都为1
        self.current_tool = None  # 人物的坐骑,初始无坐骑
        self.pz = [50000, 50000, 50000]  # 人物的初始坐标x,y,z
        Actor.ids[self.id] = self  # 一旦创建了一个人物,则将其加入静态字典中,其id为键,人物对象为值

    @classmethod
    def get_actor_from_id(cls, actor_id):  # 静态方法,通过id获取人物对象
        if actor_id in cls.ids:
            return cls.ids[actor_id]
        else:
            return None

    def ride(self, obj):  # 人物的骑乘动作,obj是宠物实例
        self.current_tool = obj  # 设置本人物当前骑乘的宠物
        self.step = obj.step  # 将本人物的移动速度切换为宠物的移动速度
        obj.owner = self  # 将宠物的主人更改为本人物

    def move_me(self):
        while True:
            for k in range(0, 3):  # 循环从三个坐标方向读取状态
                if self.trans_state[k] == 0:  # 如果是停止状态
                    pass
                elif self.trans_state[k] == 1:  # 如果正向移动状态
                    if self.pz[k] < (Actor.pz_max[k] - self.step):  # 判断移动后是否撞界
                        self.pz[k] += self.step
                    else:
                        self.pz[k] = Actor.pz_max[k]
                else:  # 如果是反向移动状态
                    if self.pz[k] > self.step:  # 判断移动后是否撞界
                        self.pz[k] -= self.step
                    else:
                        self.pz[k] = 0
            sys.stdout.write(f'{time.ctime()}: {self.name}状态:{self.trans_state} 坐标:{self.pz}\n')
            time.sleep(0.25)


class TransTool:  # 宠物类
    def __init__(self, name, step, owner=None):  # owner=None表示初始创建的宠物,无归属
        self.name = name
        self.step = step
        self.owner = owner


class Action(threading.Thread):  # 动作线程
    def __init__(self, name, act):  # act是人物实例
        threading.Thread.__init__(self, name=name)
        self.actor = act

    def run(self):  # 重写线程的run方法
        global command_list  # 动作指令设为全局变量
        t = threading.Thread(target=self.actor.move_me)  # 启动一个子线程,执行人物的移动方法
        t.setDaemon(True)  # 设置守护,可以跟随主线程的结束而结束,守护必要要在启动之前设置
        t.start()  # 启动移动的子线程
        while True:
            event.wait()  # 等待接收到新的动作指令
            if command_list[0] == 'all' or command_list[0] == self.name:  # 判断新的动作指令是否与本线程相关
                lock.acquire()  # 相关时,则获取线程锁,更改本线程人物的移动状态
                self.actor.trans_state = command_list[1]
                lock.release()  # 更改后随即释放线程锁
            event.clear()  # clear方法使事件线程重新阻塞


if __name__ == '__main__':
    actors = []  # 人物列表
    threads = []  # 子线程列表
    for i in range(1, 6):  # 循环创建5个人物
        actors.append(Actor('A' + str(i), 'actor' + str(i), 123))
    for i in range(1, 6):  # 循环给5个人物配备坐骑,坐骑的移动速度以2的倍数递增
        actors[i - 1].ride(TransTool('tool' + str(i), 2 ** (i - 1)))
    for i in range(1, 6):  # 循环给5个人物创建子线程
        threads.append(Action('Thread' + str(i), act=actors[i - 1]))
    for t in threads:  # 循环给5个子线程设置守护,并启动
        t.setDaemon(True)  # 守护必须在子线程启动前设置
        t.start()  # 启动子线程
    while True:
        lock.acquire()  # 改变动作指令前,先获取线程锁
        command_list = [['all', 'Thread1', 'Thread2', 'Thread3', 'Thread4', 'Thread5'][random.randint(0, 5)], [random.randint(0, 2), random.randint(0, 2), random.randint(0, 2)]]
        lock.release()  # 更改动作指令后,立即释放线程锁
        sys.stdout.write(f'新动作指令:{command_list}\n')
        event.set()  # 释放事件线程,触发子线程的wait后的程序代码执行
        time.sleep(1)  # IO时间阻塞

 

posted @ 2021-09-24 01:09  张永谊  阅读(269)  评论(0)    收藏  举报