zoukankan      html  css  js  c++  java
  • 多线程

    线程的特点

    线程是程序运行中的最基本单元,在一个进程内有且至少有一个进程。

     进程:内存独立,CPU独立,速率低共享数据难,安全性高

     线程:内存共享,CPU使用独立,是cpu最小的执行单位

    线程的创建方法

    1.直接实例化Thread类

       t = Thread(target=task)
        t.start()
    
        task()
        #执行顺序不固定 如果开启线程速度足够快  可能子线程先执行
        print("主线程over")
        print("1",current_thread())

    2.创建类覆盖Thread中的run方法

    class MyThread(Thread):
        def run(self):
            print("子线程run!")
    m = MyThread()
    m.start()
    print("主线over")

    使用方法和进程一样,但是开启线程的代码可以放在任何位置,开启进程的方法只能放在__name__==__main__中

    在同一进程中线程间数据共享

    from threading import Thread
    
    a = 10
    def task():
        global a
        print("子 running...")
        a = 20
    
    t1 = Thread(target=task)
    t1.start()
    
    t1.join() # 主线程等待子线执行完毕
    print(a)
    
    ==》
    子 running...
    20

    进程与线程效率

    开启一百个进程

    def task():
        pass
    
    if __name__ == '__main__':
        st_time=time.time()
        for a in range(100):
            
            t=Process(target=task)
            t.start()
    
        print(time.time()-st_time)
    
    ==3.447035074234009  开启一百个进程花费的时间

    开启一百个线程

    def task():
        pass
    
    if __name__ == '__main__':
        st_time = time.time()
        for a in range(100):
    
            t=Thread(target=task)
            t.start()
    
        print(time.time()-st_time)
        print('over')
    ==0.014977693557739258

    由此可见线程的开销远远小于进程的开销

    守护线程

    def task():
    print('1run')
    time.sleep(3)
    print('1over')

    def task1():
    print('2run')
    time.sleep(6)
    print('2over')

    t=Thread(target=task)
    t1=Thread(target=task1)
    t.start()
    t1.daemon=True
    t1.start()
    print('over')
    ==>
    1run
    2run
    over
    1over

    主线程代码执行完后不会立即结束,会等待其他非守护进程

    死锁

    当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源要想使用必须同时具备两把锁这时候程序就会进程无限卡死状态 ,这就称之为死锁

    lock1 = Lock()
    
    # 筷子
    lock2 = Lock()
    
    def eat1():
        lock1.acquire()
        print("%s抢到了盘子" % current_thread().name)
        time.sleep(0.5)
        lock2.acquire()
        print("%s抢到了筷子" % current_thread().name)
    
        print("%s开吃了!" % current_thread().name)
        lock2.release()
        print("%s放下筷子" % current_thread().name)
    
        lock1.release()
        print("%s放下盘子" % current_thread().name)
    
    def eat2():
        lock2.acquire()
        print("%s抢到了筷子" % current_thread().name)
    lock1.acquire()
    print("%s抢到了盘子" % current_thread().name) print("%s开吃了!" % current_thread().name) lock1.release() print("%s放下盘子" % current_thread().name) lock2.release() print("%s放下筷子" % current_thread().name) t1 = Thread(target=eat1) t2 = Thread(target=eat2) t1.start() t2.start() ==》 Thread-1抢到了盘子 Thread-2抢到了筷子

    如上所示,两个锁可以看作两个许可,线程需要同时拿到两把锁才可以正常运行,当两个线程各拿到一把锁的时候双方都无法正常进行下去,这就出现了死锁

    如何避免死锁问题  
            锁不要有多个,一个足够
            如果真的发生了死锁问题,必须迫使一方先交出锁

    Rlock

    称之为递归锁或者可重入锁,Rlock不使用用来解决死锁问题的

    与Lock唯一的区别:
        Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次
        如果一个线程已经执行过acquire 其他线程将无法执行acquire

    信号量

    可以现在被锁定的代码 同时可以被多少线程并发访问

    用途: 仅用于控制并发访问   并不能防止并发修改造成的问题

    from threading import Semaphore, Thread
    import time
    
    s = Semaphore(5)
    def task():
        s.acquire()
        print("子run")
        time.sleep(3)
        print("子over")
        s.release()
    
    for i in range(10):
        t = Thread(target=task)
        t.start()
  • 相关阅读:
    spart快速大数据分析学习提纲(一)
    Zookeeper的设计模式之观察者模式(十)
    shuffle机制和TextInputFormat分片和读取分片数据(九)
    MapReduce程序开发之流量求和(八)
    分布式系统间通信之RPC简单Demo(七)
    使用JAVA客户端对HDFS进行代码编写(五)
    分布式系统间通信之RPC的基本概念(六)
    DataNode工作原理(四)
    NameNode元数据的管理机制(三)
    javaweb项目部署到服务器(树莓派)上全过程——部署步骤记录与总结
  • 原文地址:https://www.cnblogs.com/duGD/p/10976153.html
Copyright © 2011-2022 走看看