• 6.线程


    线程

    1.线程

    # 线程
    """
    进程是系统资源分配的最小单位
    线程是计算机中调调的最小单位
    一个进程里至少一个主线程
    """
    from threading import Thread
    from multiprocessing import Process
    import time,random,os
    
    # 1.多个线程是异步并发操作
    def func(i):
        time.sleep(random.random())
        print(i,os.getpid())
    
    if __name__ == "__main__":
        for i in range(10):
            t = Thread(target=func,args = (i,)) # 创建线程对象
            t.start() 
        print(os.getpid())
    
    # 2.多线程之间的数据彼此共享
    num = 1000
    lst = []
    def func():
        global num
        num -= 1
    for i in range(1000):
        t = Thread(target = func)
        t.start()
        lst.append(t)
    for i in lst:
        i.join()
    print(num) # 0
    

    2.自定义线程

    # 1. 自定义线程
    from threading import Thread,enumerate
    import os,time
    
    class My(Thread): # 必须继承Thread
        def __init__(self,name):
            super().__init__() #必须手动调用父类构造方法,才能添加成员
            self.name = name
    
        def run(self):
            print("当前进程号{},参数{}".format(os.getpid(),self.name))
    
    if __name__ == "__main__":
        t = My("好人")
        t.start()
        t.join()
        print("主进程执行结束...")
    
    # 2.线程相关属性
    """
    线程.is_alive()    检测线程是否仍然存在
    线程.setName()     设置线程名字
    线程.getName()     获取线程名字
    1.currentThread().ident 查看线程id号 
    2.enumerate()        返回目前正在运行的线程列表
    3.activeCount()      返回目前正在运行的线程数量
    """
    from threading import currentThread as ct
    from threading import enumerate ,Thread
    import time
    def func():
        time.sleep(1)
        print("当前线程号{}".format(ct().ident))
        
    if __name__ == "__main__":
        t = Thread(target = func)
        t.start()
        lst = enumerate() #线程对象列表
        print(lst,len(lst))
        res = t.is_alive()
        print(res) # True
        print(t.getName()) #Thread-1
        t.setName("下载线程") 
        print(t.getName()) # 下载线程
    
    # 3.线程的缺陷
    """
    GIL: 
        全局解释器锁
    效果: 
        同一时间,一个进程下的多个线程只能被一个cpu执行,不能实现线程的并行操作 
    原因: 
        1.历史原因
        2.python是解释型语言
    改善方法:
        1.用多进程间接实现线程的并行
        2.换一个Pypy,Jpython解释器
    	
    目前来看,还不能根本解决;
    对于io密集型任务,python 绰绰有余.
    """
    

    3.守护线程

    # 守护线程
    """
    等待所有线程全部执行结束,终止守护线程,守护所有线程
    语法:
        线程.setDaemon(True) 
    """
    from threading import Thread
    import time
    
    def func1():
        while True:
            time.sleep(1)
            print(111)
    def func2():
        time.sleep(3)
        print(222)
    
    if __name__ == "__main__":
        t1 = Thread(target = func1)
        t2 = Thread(target = func2)
        t1.setDaemon(True) # 设置守护线程
        t1.start()
        t2.start()
        t2.join()
        print("助计算")
    

    4.线程互斥锁Lock 与 信号量Semaphore

    # 1.线程数据安全锁 Lock
    from threading import Thread,Lock
    import time
    
    total = 0
    def func1(lock):
        global total
        lock.acquire() # 加锁方式一
        for i in range(10000):
            total += 1
        lock.release() #解锁
    
    def func2(lock):
        global total
        with lock: # 加锁方式二 : 自动完成加锁解锁
            for i in range(10000):
                total -= 1
    
    if __name__ == "__main__":
        lst = []
        lock = Lock() # 创建锁对象
        for i in range(10):
            t1 = Thread(target = func1,args = (lock,))
            t1.start()
            t2 = Thread(target = func2,args = (lock,))
            t2.start()
            lst.append(t1)
            lst.append(t2)       
        for i in lst:
            i.join()
        print(total) # 0
        
    # 2.Semaphore : 线程信号量
    from threading import Semaphore ,Thread
    import time,random
    
    def func(i,sem):
        time.sleep(random.random())
        with sem: # 上锁
            print("{}唱歌".format(i))
            time.sleep(random.randrange(2,4))
            print("{}走了".format(i))
    
    if __name__ == "__main__":
        sem = Semaphore(3) # 创建锁对象,同一时间给3个线程加锁
        for i in range(10):
            t = Thread(target=func,args=(i,sem))
            t.start()
        print("主线程结束`~")    
    

    5.死锁Lock与递归锁RLock

    from threading import Thread,Lock,RLock
    import time
    # 1.语法上死锁
    """
    只上锁,不解锁,程序阻塞
    """
    # 2.逻辑上的死锁
    """
    两把不同的所同时上锁
    """
    lock1 = Lock()
    lock2 = Lock()
    def eat1(name):
        lock1.acquire()
        print("{}抢到了面条~~".format(name))
        lock2.acquire()
        print("{}抢到了筷子~~".format(name))
        print("开始吃面条~~")
        time.sleep(1)
        lock2.release()
        print("{}放下了筷子~~".format(name))
        lock1.release()
        print("{}放下了面条~~".format(name))
    
    def eat2(name):
        lock2.acquire()
        print("{}抢到了筷子~~".format(name))
        lock1.acquire()
        print("{}抢到了面条~~".format(name))
        print("开始吃面条~~")
        time.sleep(1)
        lock1.release()
        print("{}放下了面条~~".format(name))
        lock2.release()
        print("{}放下了筷子~~".format(name))
        
    if __name__ == "__main__":
        lst1 = ["熊大","熊二"]
        lst2 = ["贾英贺","光头强"]
        for i in lst1:
            Thread(target =eat1,args = (i,)).start()
        for i in lst2:
            Thread(target =eat1,args = (i,)).start()
    
    # 3.解决办法 
    """
    解决办法一:
        递归锁 : 是专门解决死锁问题
        连续上锁形同虚设,可以快速开锁
    解决办法二:
        尽量使用一把锁解决问题,不要使用嵌套锁,容易逻辑死锁
    """
    # 基本语法
    lock = RLock() # 创建递归锁
    lock.acquire()
    lock.acquire()
    lock.release()
    lock.release()
    print(666)
    

    6.事件Event

    # 事件Event
    """
    wait : 动态加阻塞
    is_set : 获取内部成员属性值
    clear : 把成员属性值舍尾False
    set : 把成员属性值设为True
    """
    from threading import Thread ,Event
    import time,random
    
    # 连接远程数据库
    # 检测线路
    def check(e):
        print("检测中~")
        time.sleep(1)
        print("检测账号中~")
        time.sleep(1)
        print("检测密码中~")
        time.sleep(random.randrange(1,4))
        e.set() # 检测OK,放行
    
    # 连接线程
    def connect(e):
        sign = False
        for i in range(1,4):
            e.wait(1) # 最多阻塞1秒
            if e.is_set():
                print("连接成功~~")
                sign = True
                break
            else:
                print("连接第{}失败~~".format(i))
         # 如果没成功,抛出超时异常       
        if sign ==False:
            raise TimeoutError
            
    if __name__ == "__main__":
        e = Event() # 创建事件对象
        t = Thread(target=check,args = (e,)).start()
        t = Thread(target=connect,args = (e,)).start()
    

    7.线程队列

    # 线程队列
    """
    put 存放数据 超出队列长度阻塞
    get 获取数据 超出队列长度阻塞
    put_nowait  存放数据 超出队列长度报错
    get_nowait  获取数据  超出队列长度报错
    """
    # 1.Queue 队列  : 先进先出,后进后出
    from queue import Queue
    q = Queue()
    q.put(11)
    q.put(22)
    print(q.get())  #11
    print(q.get())  #22
    # print(q.get()) #程序阻塞,队列没有数据了
    
    q = Queue(2) # 队列最多存放2个元素
    q.put(1)
    q.put(2)
    # q.put(3) # 阻塞
    
    # 2.LifoQueue 队列 : 先进后出,后进先出
    from queue import LifoQueue
    lq = LifoQueue()
    lq.put(111)
    lq.put(222)
    print(lq.get()) # 222
    print(lq.get()) # 111
    
    # 3.PriorityQueue 队列
    """
    按照优先级排序存放数据 (默认从小到大),获取数据从小到大
        可以对数字,字母,容器进行排序
    注意:
        队列里面只能存放同一类型的数据,不能混杂其他类型数据
    """
    from queue import PriorityQueue
    
    # (1) 对数字排序
    pq = PriorityQueue()
    pq.put(22)
    pq.put(11)
    pq.put(33)
    print(pq.get()) 
    print(pq.get())
    print(pq.get())
    
    # (2)多个类型数据
    """
    pq.put(11)
    pq.put("aa")
    # 错误 : '<' not supported between instances of 'str' and 'int'
    """
    
  • 相关阅读:
    解决mysql-8.0.18 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
    剑指Offer面试题:28.连续子数组的最大和
    Java BigDecimal
    蓝桥杯 分考场 JAVA
    蓝桥杯 合根植物 JAVA
    蓝桥杯 大臣的旅费 JAVA
    蓝桥杯 危险系数 JAVA
    蓝桥杯 幸运数 JAVA
    【转】对memcached使用的总结和使用场景
    【转】Memcached管理与监控工具----MemAdmin
  • 原文地址:https://www.cnblogs.com/jia-shu/p/14233075.html
Copyright © 2020-2023  润新知