zoukankan      html  css  js  c++  java
  • (8)什么是线程(如何开启线程)以及线程的其他属性

    为什么会出现线程

    进程的缺点:

    1、非常消耗资源,计算机不能无限开启子进程

    2、如果开了过多的进程,cpu的切换进程的模式下是非常耗时的

    因为进程的缺点,线程的出现就是为了解决进程的缺点,线程的开销小于进程

    1、所以线程就是轻量级的进程

    2、一个进程里面至少有一个线程

    3、线程就是具体干活的,执行任务的

    PS:进程相当于一座工厂,线程相当于干活的人

    PS:进程是一个资源的实体单位,而cpu操作的最小单位是线程

    理论案例:

    QQ是一个主进程

    QQ内有几个功能

    1、聊天

    2、支付

    3、视频

    PS:如果没有线程,就要开3个进程,这样计算机的消耗就会变大

    PS:线程的启动速度要高于进程的速度

    开启QQ主进程后,下面所有的功能就交给线程去执行,这样既对计算机的资源消耗低了,而且速度也快了

    线程的好处

    1、线程的开启速度快于进程

    2、一个进程下的线程和线程之间是共享进程的资源

    3、cpu在线程之间的切换速度远快于进程

    PS:同一个进程下的数据在线程之间是共享的

    线程和进程使用的场景

    线程的使用场景:有大量IO存在的时候,使用线程  # IO就是一个读写的过程,包括网络请求

    进程的使用场景:有密集计算的时候使用进程  

    开启线程的方式有两种

    1、函数的方式

    import time
    from threading import Thread # 从threading 包导入Thread模块,Thread模块就是开启子线程的

    def task(arg):
    print("%s is running..."% arg)
    time.sleep(1) #这个模拟IO
    print("%s is done..."% arg)

    if __name__ == '__main__':
    t = Thread(target=task,args=('子线程,')) #这是开启子线程,子线程肯定是在主线程里面开启
    t.start() #子线程在开启的瞬间就执行了
    print('主线程') #这里为什么是主线程,因为运行整段程序的时候是需要开一个进程,进程里面就有线程

    PS:子线程的开启代码写法和主线程基本一样
    PS:子线程要快于主线程
    PS:开启子线程后,下面运行的肯定是主线程,而开启子进程后面运行的肯定是主进程

    2、类的方式

    from threading import Thread

    class MyThread(Thread): #继承包中的开启子进程模块
    def run(self): #重新定义模块下的run函数
    print("hell0")

    if __name__ == '__main__':
    t = MyThread()
    t.start()
    print('主线程')

     

    线程和进程速度对比实例

    import time
    from multiprocessing import Process
    from threading import Thread

    def task(arg):
    print("%s is running..."%arg)
    time.sleep(1) #这个模拟IO
    print("%s is done..." %arg)


    if __name__ == '__main__':
    t = Thread(target=task,args=('子线程',))
    p = Process(target=task,args=('子进程',))
    t.start()
    p.start()
    print('主线程')

    PS:子线程先开启,然后主线程,子进程要等很久才开启,由于子进程开启需要向操作系统申请内存空间,在申请资源,所以进程的速度慢于线程

    同一个进程下开启线程共享数据

    from threading import Thread

    x = 100

    def task():
    global x # x定义成全局
    x = 0

    if __name__ == '__main__':
    t = Thread(target=task)
    t.start() #开启一个线程
    print(x)
    PS:可以看到线程下的程序运行时候把x的值已经修改了,说明线程下的数据是共享的,而在进程下是无法修改的,所以进程的数据是不共享的

    线程的其他属性

    1、p.pid() :  #获取进程id
    2、os.getpid() :  #获取进程id
    3、os.getppid() :  #获取父进程id
    4、p.name:  #进程的名称
    5、p.daemon: #默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
    6、p.is_alive():  #如果p仍然运行,返回True
    7、current_thread() #这是一个类,代表当前的线程,这个类下有很多方法,比如current_thread().name代当前线程的名称,也可以用t.name来获取当前线程的名称
     8、active_count() #这是一个类,查看当前线程活跃数

    1、t.is_alive() # 查看线程是否存活

    from threading import Thread

    def task():
    print('xxxxxxxxx')

    if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    print(t.is_alive()) #查看线程是否存活,存活就是True,死了就是False
    print('主')

    2、t.join() # 等待子线程执行完毕

    例1:
    from threading import Thread

    def task():
    print('xxxxxxxxx')

    if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    t.join() #等待子线程执行完毕
    print(t.is_alive())
    print('主')
    PS:由于子线程开启是异步的,所以如果用join等待子线程执行完毕再查看线程是否存活,肯定是False
    例:2
    import time
    from threading import Thread

    def task():
    print('xxxxxxxxx')
    time.sleep(1) #这个模拟IO

    if __name__ == '__main__':
    start = time.time()
    t_l = []
    for i in range(10):
    t = Thread(target=task)
    t_l.append(t) # 将线程放入列表
    t.start()
    for t in t_l:
    t.join() #等待每个线程结束
    end = time.time()
    print(end-start)
    PS:利用for循环一次开启10个线程,然后用join方法等待线程执行完毕,计算所有线程执行的时间,由于线程之间是异步的,所以同时开了10个线程,10个线程同时睡了1秒,所以结果开启线程到线程结束只用了一秒

    current_thread类下方法使用(.name查看当前线程名) 

    from threading import Thread,current_thread #必须从threading包下倒入current_thread类

    def task():
    print('xxxxxxxxx')
    print(current_thread().name) #这里就是用类current_thread().name查看当前线程名

    if __name__ == '__main__':
    t = Thread(target=task,name='QQ')
    t.start()
    print('主')

    active_count方法查看当前活跃的线程数

    from threading import Thread,active_count #从threading包下倒入active_count方法

    def task():
    print('xxxxxxxxx')

    if __name__ == '__main__':
    t = Thread(target=task,name='QQ')
    t.start()
    print(active_count()) #查看当前活跃的线程数
    print('主')

    守护线程

    守护进程:守护的是父进程

    守护线程:守护的是进程内的其他线程(比如一个进程内有10个线程,有一个是守护线程,这个守护线程要等另外的9个线程执行完毕才会死),守护的是整个进程的运行周期

    开启守护线程

    import time
    from threading import Thread,current_thread #current_thread定义守护线程的名字

    def task():
    print('%s is running...'%current_thread().name) # 打印守护线程的名字
    time.sleep(1) #这个模拟IO
    print('%s is done...' % current_thread().name)

    if __name__ == '__main__':
    t = Thread(target=task,name='守护进程')
    t.daemon=True #daemon就是开启守护线程
    t.start()
    print('主线程')

    守护线程实例

    from threading import Thread
    import time

    def foo():
    print(123)
    time.sleep(3) #这个就是模拟IO
    print('end123')

    def bar():
    print(456)
    time.sleep(1) #这个就是模拟IO
    print('end456')

    t1 = Thread(target=foo)
    t2 = Thread(target=bar)
    t1.daemon=True
    t1.start()
    t2.start()
    print('main---------')

    PS:开启了两个线程t1和t2,t1设置了一个守护线程,t1必须等着t2执行完以及主线程执行完才会死亡,t1.start和t2.start开启线程时候会立马执行函数,t1执行foo函数然后会睡3秒,这时候同时t2执行bat函数然后睡1秒后执行完毕,主线程执行完毕,所以t1子线程里面最后一个不会执行,因为主线程已经执行完毕,守护进程直接死亡,t1这个子线程结束

  • 相关阅读:
    java09-8大基本类型的包装类、装箱拆箱
    java08-枚举
    类加载-双亲委托机制
    java虚拟机05-虚拟机加载类机制&类加载器
    java虚拟机04-内存分配与回收策略
    java-07 内部类、匿名内部类、局部内部类、lambda
    从0开始的Python学习012数据结构&对象与类
    从0开始的Python学习011模块
    从0开始的Python学习010return语句&DocStrings
    从0开始的Python学习009参数
  • 原文地址:https://www.cnblogs.com/shizhengquan/p/10262453.html
Copyright © 2011-2022 走看看