• 线程及其开启方式和方法


    初识线程

    在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程,cpu真正的执行单位是线程

    这和在工厂中很像,在工厂中,每个车间都有房子,而且每个车间默认有一条流水线

    所以,我们可以吧操作系统和工厂进行类比:

    操作系统 ===> 工厂
    进程 ===> 车间
    线程 ===> 流水线
    cpu  ===> 电源
    线程:cpu最小的执行单位
    进程:资源集合/资源单位.
    线程运行 = 运行代码
    进程运行 = 各种资源 + 线程
    

    右键运行:
    申请内存空间,先把解释器丢进去并且把代码丢进去(进程做的),运行代码(线程).

    进程和线程的区别:

    过程描述的区别

    线程==》单指代码的执行过程
    进程==》资源的申请与销毁的过程
    

    进程内存空间彼此隔离
    同一个进程下的线程共享资源.

    进程和线程的创建速度
    进程需要申请资源开辟空间 慢
    只是告诉操作系统一个执行方案 快

    线程开启的俩种方式

    线程开启的方式和进程十分的类似,我就不进行详细说明了,他也是分为方法和类俩种

    线程用的是throading模块

    方式一

    from threading import Thread
    import time
    def task():
        print('线程 start')
        time.sleep(2)
        print('线程 end')
    
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()  # 告诉操作系统开一个线程  .
    
        print('主')
    

    方式二

    from threading import Thread
    import time
    # 进程等待所有线程结束才会结束
    
    class Myt(Thread):
        def run(self):
            print('子线程 start')
            time.sleep(5)
            print('子线程 end')
    
    t = Myt()
    t.start()
    print('主线程')
    

    线程和进程创建速度比较

    进程在创建时,开启子进程需要申请资源开辟空间,较慢

    而线程在开启子线程只是告诉操作系统一个执行方案,较快

    我们可以用代码进行比较

    from threading import Thread
    from multiprocessing import Process
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is end')
    
    
    if __name__ == '__main__':
        t = Thread(target=task,args=('子线程',))
        p = Process(target=task,args=('子进程',))
        # t.start()
        p.start()
        print('主')
    开启子线程的打印效果:
    
    子线程 is running
    主
    子线程 is end
    
    ==================
    
    开启子进程打印效果:
    
    主
    子进程 is running
    子进程 is end
    
    ==================
    
    俩者都开启的打印效果:
    子线程 is running
    主
    子进程 is running
    子线程 is end
    子进程 is end
    

    子线程共享资源

    from threading import Thread
    import time, os
    
    x = 100
    def task():
        global x
        x = 50
        print(os.getpid()) # 12024
    
    
    if __name__ == '__main__':
    
        t = Thread(target=task)
        t.start()
        time.sleep(2)
        print(x) # 50
        print(os.getpid()) # 12024
    

    x的值被改变了,说明用的是同一个资源,也就是说,同一进程下的线程共享同一资源

    线程的join方法

    线程的join的使用方法大体上和进程还是有些类似的,话不多说,直接上代码吧

    from threading import Thread
    import time
    def task():
        print('子线程 start')
        time.sleep(2)
        print('子线程 end')
    
    t = Thread(target=task)
    t.start()
    t.join() # 等待子线程运行结束
    print('主线程')
    

    主线程会在子线程运行完之后再执行

    多线程的join

    当三个线程运行时间分别为1,2,3秒,执行时间会是多少呢?

    from threading import Thread
    import time
    def task(name,n):
        print(f'{name} start')
        time.sleep(n)
        print(f'{name} end')
    
    t1 = Thread(target=task,args=('线程1',1))
    t2 = Thread(target=task,args=('线程2',2))
    t3 = Thread(target=task,args=('线程3',3))
    start = time.time()
    t1.start()
    t2.start()
    t3.start()
    t1.join() # 111s
    t2.join() #
    t3.join()
    end = time.time() # 3.003263235092163
    # 思考一下 在单核的情况下 多个线程是如何利用cpu的
    print(end-start)
    
    
    # print('主线程')
    

    在单核的情况下,cpu先执行t1的start,遇到io之后直接跳到t2,在t2遇到io后又会跳到t3,等t1sleep完之后再执行t1的end,依次推类

    将这里和之前进程相比较,也可以发现线程的速度比进程快的多得多

    了解进程的join

    from multiprocessing import Process
    from threading import Thread
    import time
    def task():
        print('进程 开启')
        time.sleep(10)
        print('进程 结束')
    def task2():
        print('子线程 开启')
        time.sleep(2)
        print('子线程 结束')
    
    if __name__ == '__main__':
        p = Process(target=task)
        t = Thread(target=task2)
        t.start() # 开线程
        p.start() # 开进程
        print('子进程join开始')
        p.join() # 主进程的主线程等待子进程运行结束
        print('主')
    

    结果为:

    子线程 开启
    子进程join开始
    进程 开启
    子线程 结束
    进程 结束
    主
    

    可以发现,以往都说p.join是主进程等待子进程运行结束,现在我们发现,主进程的子线程并没有等待子进程运行结束,只有主进程的主线程才等待子进程运行结束

    线程的其他相关用法

    线程除了最常用的join,还有其他用法,其中大部分都和进程差不多,这里就不一一赘述,直接用代码来展示吧

    from threading import Thread,currentThread,enumerate,activeCount
    # import threading
    import time
    # threading.current_thread()
    # threading.current_thread()
    
    def task():
        print('子线程 start')
        time.sleep(2)
        print('子线程 end')
        print(enumerate())
        # print(currentThread(),'子线程')
    if __name__ == '__main__':
       t1 = Thread(target=task)
       t2 = Thread(target=task)
       t1.start()
       t2.start()
    
       # print(t1.is_alive()) # True
       # print(t1.getName()) # Thread-1
       # print(t2.getName()) # Thread-2
       # t1.setName('班长')
       # print(t1.getName())
       # print(currentThread().name)
       # print(enumerate()) # [<_MainThread(MainThread, started 1856)>, <Thread(Thread-1, started 6948)>, <Thread(Thread-2, started 3128)>]
       # print(activeCount()) # 3
       # print(len(enumerate())) # 3
    

    在这里,我们已经写了一个from threading import Thread之后,还可以写import threading,这样并不会占用更多的空间,当你需要别的东西的时候可以直接threading.xx就可以了

    守护线程

    守护的是进程的运行周期

    def task():
        print('守护线程开始')
        print(currentThread())
        time.sleep(20)
        # print('守护线程结束')
    
    def task2():
        print('子线程 start')
        time.sleep(5)
        print(enumerate())
        print('子线程 end')
    
    if __name__ == '__main__':
        t1 = Thread(target=task)
        t2 = Thread(target=task2)
        t1.daemon = True
        t2.start()
        t1.start()
        print('主')
    

    线程的守护线程会在进程结束的时候结束,也就是task中的print(currentThread())会在print('主')之后打印出来。但是task线程在sleep的时候主线程结束了,所以 最后的守护线程结束不会被打印

  • 相关阅读:
    请为新诗赐题
    ***套接字连接已中止。这可能是由于处理消息时出错或远程主机超过接收超时或者潜在的网络资源问题导致的
    关于sum(int)报错:将expression转化为数据类型int时发生算术溢出错误
    【SSB】清空service broker中的队列
    【SSB 】Handling and Removing Poison Messages
    一淘网的系统架构
    WCF服务器已拒绝客户端凭据
    Web 安全威胁与对策
    SQL Prompt 4 破解步骤
    【SSB】Activation Execution Context
  • 原文地址:https://www.cnblogs.com/jie9527-/p/11537483.html
Copyright © 2020-2023  润新知