多线程

作者: wangyu2488 | 来源:发表于2019-12-22 14:27 被阅读0次

    2019年12月19日

    一.概念

    1.进程

    image.png

    2.线程

    image.png

    3.多线程开发 推荐用threading

    image.png
    import threading
    
    # 当前线程对象
    t = threading.current_thread()
    # 当前线程名
    print(t.name)
    
    # 返回当前处于活动状态的线程个数
    print(threading.active_count())
    # 当主线程对象
    t = threading.main_thread()
    # 主线程名
    print(t.name)
    
    image.png

    二.创建线程

    image.png

    1.方法1创建线程

    # coding=utf-8
    
    import threading
    import time
    
    # 线程体函数
    def thread_body():
        # 当前线程对象
        t = threading.current_thread()
        for n in range(2):
            # 当前线程名
            print('第{0}次执行线程{1}'.format(n, [t.name](http://t.name/)))
            # 线程休眠
            time.sleep(1)
        print('线程{0}执行完成!'.format(t.name))
    
    # 主函数
    def main():
        # 创建线程对象t1
        t1 = threading.Thread(target=thread_body)
        # 启动线程t1
        t1.start()
    
        # 创建线程对象t2
        t2 = threading.Thread(target=thread_body, name='MyThread')
        # 启动线程t2
        t2.start()
    
    if __name__ == '__main__':
        main()
    

    休眠可以看出是交替执行

    image.png

    2.方法2创建线程 (继承线程类)

    # coding=utf-8
    
    import threading
    import time
    
    class MyThread(threading.Thread):
        def __init__(self, name=None):
            super().__init__(name=name)
    
        # 线程体函数
        def run(self):
            # 当前线程对象
            t = threading.current_thread()
            for n in range(2):
                # 当前线程名
                print('第{0}次执行线程{1}'.format(n, t.name))
    
                # 线程休眠
                time.sleep(1)
            print('线程{0}执行完成!'.format(t.name))
    
    # 主函数
    def main():
        # 创建线程对象t1
        t1 = MyThread()
        # 启动线程t1
        t1.start()
    
        # 创建线程对象t2
        t2 = MyThread(name='MyThread')
        # 启动线程t2
        t2.start()
    
    if __name__ == '__main__':
        main()
    

    三.线程的管理 (等待线程结束和线程停止)

    image.png

    1.等待线程结束例子(join)

    # coding=utf-8
    
    import threading
    import time
    
    # 共享变量
    value = 0
    
    # 线程体函数
    def thread_body():
        global value
        # 当前线程对象
        print('ThreadA 开始...')
        for n in range(2):
            print('ThreadA 执行...')
            value += 1
            # 线程休眠
            time.sleep(1)
        print('ThreadA 结束...')
    
    # 主函数
    def main():
        print('主线程 开始...')
        # 创建线程对象t1
        t1 = threading.Thread(target=thread_body, name='ThreadA')
        # 启动线程t1
        t1.start()
        # 主线程被阻塞,等待t1线程结束
        t1.join()
        print('value = {0}'.format(value))
        print('主线程 结束...')
    
    if __name__ == '__main__':
        main()
    
    image.png

    2.线程停止 (while循环的需要添置,通过全局变量来控制)

    # coding=utf-8
    
    import threading
    import time
    
    # 线程停止变量
    isrunning = True
    
    # 线程体函数
    def thread_body():
        while isrunning:
            # 线程开始工作
            # TODO
            print('下载中...')
            # 线程休眠
            time.sleep(5)
        print('执行完成!')
    
    # 主函数
    def main():
        # 创建线程对象t1
        t1 = threading.Thread(target=thread_body)
        # 启动线程t1
        t1.start()
        # 从键盘输入停止指令 exit
        command = input('请输入停止指令:')
        if command == 'exit':
            global isrunning
            isrunning = False
    
    if __name__ == '__main__':
        main()
    
    image.png

    四.线程安全

    1.临界资源问题

    image.png

    销售机票例子(错误的例子)

    # coding=utf-8
    
    import threading
    import time
    
    class TicketDB:
        def __init__(self):
            # 机票的数量
            self.ticket_count = 5
    
        # 获得当前机票数量
        def get_ticket_count(self):
            return self.ticket_count
    
        # 销售机票
        def sell_ticket(self):
            # TODO 等于用户付款
            # 线程休眠,阻塞当前线程,模拟等待用户付款
            time.sleep(1)
            print("第{0}号票,已经售出".format(self.ticket_count))
            self.ticket_count -= 1
    
    # 创建TicketDB对象
    db = TicketDB()
    
    # 线程体1函数
    def thread1_body():
        global db  # 声明为全局变量
        while True:
            curr_ticket_count = db.get_ticket_count()
            # 查询是否有票
            if curr_ticket_count > 0:
                db.sell_ticket()
            else:
                # 无票退出
                break
    
    # 线程体2函数
    def thread2_body():
        global db  # 声明为全局变量
        while True:
            curr_ticket_count = db.get_ticket_count()
            # 查询是否有票
            if curr_ticket_count > 0:
                db.sell_ticket()
            else:
                # 无票退出
                break
    
    # 主函数
    def main():
        # 创建线程对象t1
        t1 = threading.Thread(target=thread1_body)
        # 启动线程t1
        t1.start()
        # 创建线程对象t2
        t2 = threading.Thread(target=thread2_body)
        # 启动线程t2
        t2.start()
    
    if __name__ == '__main__':
        main()
    

    有问题 两个5了

    image.png

    2.多线程同步[解决上面数据出错的问题]

    image.png
    # coding=utf-8
    
    import threading
    import time
    
    class TicketDB:
        def __init__(self):
            # 机票的数量
            self.ticket_count = 5
    
        # 获得当前机票数量
        def get_ticket_count(self):
            return self.ticket_count
    
        # 销售机票
        def sell_ticket(self):
            # TODO 等于用户付款
            # 线程休眠,阻塞当前线程,模拟等待用户付款
            time.sleep(1)
            print(threading.current_thread().name)
            print("第{0}号票,已经售出".format(self.ticket_count))
            self.ticket_count -= 1
    
    # 创建TicketDB对象
    db = TicketDB()
    # 创建Lock对象
    lock = threading.Lock()
    
    # 线程体1函数
    def thread1_body():
        global db, lock  # 声明为全局变量
        while True:
            lock.acquire()
            curr_ticket_count = db.get_ticket_count()
            # 查询是否有票
            if curr_ticket_count > 0:
                db.sell_ticket()
            else:
                lock.release()
                # 无票退出
                break
            lock.release()
            time.sleep(1)
    
    # 线程体2函数
    def thread2_body():
        global db, lock  # 声明为全局变量
        while True:
            lock.acquire()
            curr_ticket_count = db.get_ticket_count()
            # 查询是否有票
            if curr_ticket_count > 0:
                db.sell_ticket()
            else:
                lock.release()
                # 无票退出
                break
            lock.release()
            time.sleep(1)
    
    # 主函数
    def main():
        # 创建线程对象t1
        t1 = threading.Thread(target=thread1_body)
        # 启动线程t1
        t1.start()
        # 创建线程对象t2
        t2 = threading.Thread(target=thread2_body)
        # 启动线程t2
        t2.start()
    
    if __name__ == '__main__':
        main()
    
    image.png

    五.线程之间通信

    通信可以使用threading模块的Condition 和 Event类

    1.Condition

    image.png
    # coding=utf-8
    
    import threading
    import time
    
    # 创建条件变量对象
    condition = threading.Condition()
    
    class Stack:
        def __init__(self):
            # 堆栈指针初始值为0
            self.pointer = 0
            # 堆栈有5个数字的空间
            self.data = [-1, -1, -1, -1, -1]
    
        # 压栈方法
        def push(self, c):
            global condition
            condition.acquire()
            # 堆栈已满,不能压栈
            while self.pointer == len(self.data):
                # 等待其它线程把数据出栈
                condition.wait()
            # 通知其他线程把数据出栈
            condition.notify()
            # 数据压栈
            self.data[self.pointer] = c
            # 指针向上移动
            self.pointer += 1
            condition.release()
    
        # 出栈方法
        def pop(self):
            global condition
            condition.acquire()
            # 堆栈无数据,不能出栈
            while self.pointer == 0:
                # 等待其他线程把数据压栈
                condition.wait()
            # 通知其他线程压栈
            condition.notify()
            # 指针向下移动
            self.pointer -= 1
            data = self.data[self.pointer]
            condition.release()
            # 数据出栈
            return data
    
    # 创建堆栈Stack对象
    stack = Stack()
    
    # 生产者线程体函数
    def producer_thread_body():
        global stack  # 声明为全局变量
        # 产生10个数字
        for i in range(0, 10):
            # 把数字压栈
            stack.push(i)
            # 打印数字
            print('生产:{0}'.format(i))
            # 每产生一个数字线程就睡眠
            time.sleep(1)
    
    # 消费者线程体函数
    def consumer_thread_body():
        global stack  # 声明为全局变量
        # 从堆栈中读取数字
        for i in range(0, 10):
            # 从堆栈中读取数字
            x = stack.pop()
            # 打印数字
            print('消费:{0}'.format(x))
            # 每消费一个数字线程就睡眠
            time.sleep(1)
    
    # 主函数
    def main():
        # 创建生产者线程对象producer
        producer = threading.Thread(target=producer_thread_body)
        # 启动生产者线程
        producer.start()
        # 创建消费者线程对象consumer
        consumer = threading.Thread(target=consumer_thread_body)
        # 启动消费者线程
        consumer.start()
    
    if __name__ == '__main__':
        main()
    

    正常现象

    image.png

    2.Event

    image.png
    # coding=utf-8
    
    import threading
    import time
    
    event = threading.Event()
    
    class Stack:
        def __init__(self):
            # 堆栈指针初始值为0
            self.pointer = 0
            # 堆栈有5个数字的空间
            self.data = [-1, -1, -1, -1, -1]
    
        # 压栈方法
        def push(self, c):
            global event
            # 堆栈已满,不能压栈
            while self.pointer == len(self.data):
                # 等待其它线程把数据出栈
                event.wait()
            # 通知其他线程把数据出栈
            event.set()
            # 数据压栈
            self.data[self.pointer] = c
            # 指针向上移动
            self.pointer += 1
    
        # 出栈方法®
        def pop(self):
            global event
            # 堆栈无数据,不能出栈
            while self.pointer == 0:
                # 等待其他线程把数据压栈
                event.wait()
            # 通知其他线程压栈
            event.set()
            # 指针向下移动
            self.pointer -= 1
            # 数据出栈
            data = self.data[self.pointer]
            return data
    
    # 创建堆栈Stack对象
    stack = Stack()
    
    # 生产者线程体函数
    def producer_thread_body():
        global stack  # 声明为全局变量
        # 产生10个数字
        for i in range(0, 10):
            # 把数字压栈
            stack.push(i)
            # 打印数字
            print('生产:{0}'.format(i))
            # 每产生一个数字线程就睡眠
            time.sleep(1)
    
    # 消费者线程体函数
    def consumer_thread_body():
        global stack  # 声明为全局变量
        # 从堆栈中读取数字
        for i in range(0, 10):
            # 从堆栈中读取数字
            x = stack.pop()
            # 打印数字
            print('消费:{0}'.format(x))
            # 每消费一个数字线程就睡眠
            time.sleep(1)
    
    # 主函数
    def main():
        # 创建生产者线程对象producer
        producer = threading.Thread(target=producer_thread_body)
        # 启动生产者线程
        producer.start()
        # 创建消费者线程对象consumer
        consumer = threading.Thread(target=consumer_thread_body)
        # 启动消费者线程
        consumer.start()
    
    if __name__ == '__main__':
        main()
    

    正常现象

    image.png

    如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。

    相关文章

      网友评论

          本文标题:多线程

          本文链接:https://www.haomeiwen.com/subject/mvsonctx.html