zoukankan      html  css  js  c++  java
  • Python中的线程详解

    线程

    常用的方法
    
    import threading
    import time
    
    def hello(name):
        print('Hello %s' % name)
        # 阻塞
        time.sleep(5)
        print('阻塞了')
    
    if __name__ == '__main__':
        
        t1 = threading.Thread(target=hello, args=('zhangsan',))
        t2 = threading.Thread(target=hello, args=('lisi',))
        t1.setName('first')  # 设置线程名
        start = time.time()
        t1.start()
        t2.start()
        print('---------------')
        print(t1.getName())
        end = time.time()
        print(end-start)  # 计算时间
    
    

    运算的结果如下,可以看到遇到阻塞是直接进行了异步操作,先执行了所有的操作,然后才进行了等待操作,最后结束了程序
    gai

    
    import threading
    import time
    
    def hello(name):
        print('你好 %s' % name)
        # 阻塞
        time.sleep(5)
        print('阻塞了')
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=hello, args=('李',))
        t2 = threading.Thread(target=hello, args=('王',))
        t1.setName('aaa')  # 设置线程名
        start = time.time()
        t1.start()
        t2.start()
        t2.join()
        print('---------------')
        print(t1.getName())  # 获取线程名字
        end = time.time()
        print(end-start)  # 计算时间
    

    运算结果如下:可以看到等待了5秒后才往后执行,join()方法让线程变的毫无意义。

    gai

    继承类的线程使用方法
    import threading
    import time
    
    class MyThread(threading.Thread):
        def __init__(self, name):
            super().__init__()
            self.name = name
        def run(self):
            print('你好 %s' % self.name)
            time.sleep(5)
            print('阻塞了')
    if __name__ == '__main__':
    
        t1 = MyThread('李')
        t2 = MyThread('王')
        start = time.time()
        t1.start()
        t2.start()
        end = time.time()
        print('运行时间 %s 秒' % (end - start))  # 计算时间
    

    计算结果如下所示:
    gai

    守护进程 setDaemon

    不开的状态
    import threading
    import time
    
    def run(n):
        print('你好 %s' % n)
        time.sleep(2)
    def main():
        for i in range(5):
            t = threading.Thread(target=run, args=(i,))
            t.start()
    m = threading.Thread(target=main)
    m.start()
    print('------运行结束-----')
    

    运行结果:

    gai

    开启后的状态
    import threading
    import time
    
    def run(n):
        print('你好 %s' % n)
        time.sleep(2)
        print('我随后跑')
    def main():
        for i in range(5):
            t = threading.Thread(target=run, args=(i,))
            t.start()
    m = threading.Thread(target=main)
    m.setDaemon(True)  # 开启True将主线程设置为守护进程,主线程结束那一刻,其他子线程会同时结束,不论是否执行完毕
    m.start()
    print('------运行结束-----')
    

    运行结果如下:
    可以看到主进程结束,直接程序结束,子进程压根都没运行。这就是守护进程
    gai

    线程锁Lock

    一个进程下可以启动多个线程,多个线程共享父进程的内存空间,每个线程可以访问同一份数据,所以当多个线程同时要修改同一份数据时,就会出现错误。

    import threading
    import time
    
    class MyThread(threading.Thread):
        def run(self):
            global num
            time.sleep(1)
            num = num + 1
            msg = self.name + 'set num to' + str(num)
            print(msg)
    
    num = 0
    def test():
        for i in range(5):
            t = MyThread()
            t.start()
    
    if __name__ == '__main__':
        test()
    

    运行结果出现了不可控,线程2没有增加到2,而线程5增加到了2,这是因为没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。
    gai

    加锁
    创建锁
    lock = threading.Lock()
    锁定资源
    lock.acquire()
    释放资源
    lock.release()
    
    
    import threading
    import time
    
    class MyThread(threading.Thread):
        def run(self):
            global num
            if lock.acquire():
                time.sleep(1)
                num = num + 1
                msg = self.name + 'set num to' + str(num)
                print(msg)
                lock.release()
    
    num = 0
    lock = threading.Lock()
    def test():
        for i in range(5):
            t = MyThread()
            t.start()
    
    if __name__ == '__main__':
        test()
    

    当多个线程都修改某一个共享数据的时候,需要进行同步控制。上锁之后,结果跟我们的预期完全一致。

    互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
    gai

    递归锁RLock

    锁中包含锁

    
    import threading
    
    def run1():
        lock.acquire()  # 小锁
        global num
        num += 1
        lock.release()
        return num
    def run2():
        lock.acquire()  # 小锁
        global num2
        num2 += 1
        lock.release()
        return num2
    
    def run3():
        lock.acquire()  # 大锁
        res = run1()
        res2 = run2()
        lock.release()
        print(res, res2)
    
    if __name__ == '__main__':
        num, num2 = 0, 0
        lock = threading.RLock()  # 生成Rlock
        for i in range(10):
            t = threading.Thread(target=run3)
            t.start()
    
    while threading.active_count() != 1:  # 线程活动数量不是1,说明子线程还没运行完毕
        pass
    else:
        print('运行结束')
    

    gai

    semaphore信号量

    同时允许一定数量的线程更改数据

    import threading
    import time
    
    def run(n):
        semaphore.acquire()
        time.sleep(1)
        print('run the thread: %s' % n)
        semaphore.release()
    
    if __name__ == '__main__':
        semaphore = threading.BoundedSemaphore(3)  # 设置最多允许3个线程同时运行
        for i in range(20):
            t = threading.Thread(target=run, args=(i,))
            t.start()
    

    3个3个分批次的出现
    gai

    event事件

    实现两个或多个线程间的交互

    event.set() 会使event内部为真
    event.clear() 会使event内部为假
    event.isSet() 判断有没有被设定为真

    如果event内部为真,则wait不阻塞,否则会阻塞

    import threading
    
    def start():
        print('---start---1')
        event.wait()  # 阻塞
        print('---start---2')
    if __name__ == '__main__':
        event = threading.Event()
        t = threading.Thread(target=start)
        t.start()
        print(event.isSet())
    
    

    运行结果,程序会阻塞在start1进行不下去
    gai

    将event内部设置为真
    
    import threading
    def start():
        print('---start---1')
        event.wait()  # 阻塞
        print('---start---2')
    if __name__ == '__main__':
        event = threading.Event()
        t = threading.Thread(target=start)
        t.start()
        event.set()
        print(event.isSet())
    

    运行结果会从阻塞变为畅通
    gai

  • 相关阅读:
    Python驱动SAP GUI完成自动化(三)
    Python驱动SAP GUI完成自动化(选择布局+动态获取节点值)
    python中如何将货币数字转化成汉字大写金额
    python requests无法上传中文文件名的文件
    requests库结合selenium库共同完成web自动化和爬虫工作
    利用python第三方库提取PDF文件的表格内容
    pyinstaller打包exe文件闪退的解决办法
    pandas数据分析小知识点(一)
    java 终端输入小结,输入到数组、文件等(持续更新)
    Maven jenkins +Jmeter自动化测试
  • 原文地址:https://www.cnblogs.com/lishi-jie/p/10101393.html
Copyright © 2011-2022 走看看