• Python3学习之路~9.2 操作系统发展史介绍、进程与线程区别、线程语法、join、守护线程


    一 操作系统发展史介绍

    参考链接:http://www.cnblogs.com/alex3714/articles/5230609.html

    二 进程与线程

    进程: 对各种资源管理的集合 就可以称为进程。进程要以一个整体的形式暴露给操作系统管理,里面包含对各种资源的调用,内存的管理,网络接口的调用等。比如qq就可以称为一个进程。进程 要操作cpu , 必须要先创建一个线程。

    线程: 是操作系统最小的调度单位, 是一串指令的集合。

    进程与线程的区别?

    1.线程共享内存空间,进程的内存是独立的。
    2.线程可以直接访问其进程的数据段,进程拥有自己父进程数据段的副本。
    3.同一个进程的线程之间可以直接交流,两个进程想通信,必须通过一个中间代理来实现
    4.创建新线程很简单,创建新进程需要对其父进程进行一次克隆
    5.一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程
    6.对主线程的更改(取消,优先级更改等)可能会影响进程的其他线程的行为,对父进程的更改不会影响子进程。

    参考链接:http://www.cnblogs.com/alex3714/articles/5230609.html

    三 线程语法

    我们知道,IO操作不占用cpu,计算占用cpu。
    python多线程不适合cpu密集操作型的任务,适合io操作密集型的任务。

    线程有2种调用方式,如下:

    直接调用

    import threading
    import time
    
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    # 普通调用,程序执行完需要4秒
    # run("t1")
    # run("t2")
    
    # 两个线程并发,程序执行完仅需要2秒
    t1 = threading.Thread(target=runtask,args=("t1",))
    t2 = threading.Thread(target=runtask,args=("t2",))
    
    t1.start()
    t2.start()
    

    继承式调用

    import threading
    import time
    
    class MyThread(threading.Thread):
        def __init__(self,n):
            super(MyThread,self).__init__()
            self.n = n
    
        def run(self):#注意此处函数名必须为run
            print("task", self.n)
            time.sleep(2)
    
    t1 = MyThread("t1")
    t2 = MyThread("t2")
    
    t1.start()
    t2.start()
    
    import threading
    import time
    
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    # 使用for循环同时启动50个线程
    for i in range(50):
        t = threading.Thread(target=runtask,args=("t%s" %i,))
        t.start()
    使用for循环同时启动50个线程

    四 join

    一个程序可以看做是一个主线程,当它启动子线程后,就不再管子线程了,此时子线程与主线程是并行的关系,同时进行。所以在主线程中无法测试子线程的运行速度,如下代码实例:

    import threading
    import time
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    start_time = time.time()
    t1 = threading.Thread(target=runtask,args=("t1",))
    t2 = threading.Thread(target=runtask,args=("t2",))
    
    t1.start()
    t2.start()
    
    print(time.time()-start_time) # 输出:0.0
    View Code

     那么如果我一定要测试所有子线程运行的总时间怎么办呢?可以通过t.join()设置在主线程中等待子线程执行完成。join()的作用就是使子线程执行完毕后,主线程才继续往下走。

    import threading
    import time
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    start_time = time.time()
    t1 = threading.Thread(target=runtask,args=("t1",))
    t2 = threading.Thread(target=runtask,args=("t2",))
    
    t1.start()
    t2.start()
    
    t1.join() #等待t1执行完成
    t2.join() #等待t2执行完成
    
    print(time.time()-start_time) # 输出:2.0011143684387207
    计算2个线程执行完所需的时间
    import threading
    import time
    
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    t_objs = [] #存线程实例
    start_time = time.time()
    
    for i in range(50):
        t = threading.Thread(target=runtask,args=("t%s" %i,))
        t.start()
        t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里
    
    
    for t in t_objs: # 循环线程实例列表,等待所有线程执行完毕
        t.join()
    
    print(time.time()-start_time) # 输出:2.006114959716797
    计算50个线程执行完毕所需的时间

    注意:一定要把所有线程都启动后,才能执行t.join()等待。如果启动完一个线程就等待,然后才启动下一个线程,那么2个线程就变成了串行,完全失去了并发的功能。举例:

    import threading
    import time
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    start_time = time.time()
    t1 = threading.Thread(target=runtask,args=("t1",))
    t2 = threading.Thread(target=runtask,args=("t2",))
    
    t1.start()
    t1.join()
    
    t2.start()
    t2.join()
    
    print(time.time()-start_time) # 输出:4.0002288818359375
    View Code

    如下示例,通过threading.active_count()可以查看当前活跃的线程个数,虽然启动了2个子线程,但其实一共有3个线程在运行。通过threading.current_thread()可以看出谁是主线程,谁是子线程。第一个启动的线程并不是主线程,主线程就是程序本身。

    import threading
    import time
    def runtask(n):
        print("task",n)
        time.sleep(2)
        print(threading.current_thread())
    
    t1 = threading.Thread(target=runtask,args=("t1",))
    t2 = threading.Thread(target=runtask,args=("t2",))
    t1.start()
    t2.start()
    print(threading.current_thread())
    print(threading.active_count())
    ####输出:
    ####task t1
    ####task t2
    ####<_MainThread(MainThread, started 8504)>
    ####3
    ####<Thread(Thread-1, started 9996)>
    ####<Thread(Thread-2, started 9976)>
    View Code

    五 守护线程

    守护线程:一个主线程可以发起多个守护线程,这些守护线程都是为主线程服务的,一旦主线程挂了,守护线程随之挂掉。守护线程的用途有帮助主线程管理资源、打开文件、监听端口、监听一些新的链接、把垃圾资源回收等,它可以干很多事情,由主线程定义。

    子线程和守护线程的区别

    虽然在启动子线程后,主线程和子线程是同时运行,但是当主线程运行完后,它还是会等待所有子线程都运行完毕,程序才会退出。如下示例,可以明显感觉到主线程运行完后,程序又等待了2秒才退出。
    可以在子线程start之前,通过t.setDaemon(True)将子线程设置为守护线程。此时再运行程序,你就会发现,主线程运行完成后,程序直接退出,没有等待子线程。

    import threading
    import time
    
    def runtask(n):
        print("task",n)
        time.sleep(2)
    
    for i in range(50):
        t = threading.Thread(target=runtask,args=("t%s" %i,))
        ####将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务
        # t.setDaemon(True) #把当前线程设置为守护线程,
        t.start()
    
    print("main thread finished")
    守护线程

    所以,主线程一旦创建了子线程,子线程就完全独立了,它的运行不会再受主线程的控制。而守护线程不同,它的运行依赖于主线程,一旦主线程执行完毕,守护线程随之终止。

    守护线程的用途:比如说现在写一个socketserver,每有一个用户连接,你就为其分配一个子线程,那么当你希望手动宕掉socketserver时,肯定不希望它等每个子线程都断完成后,才宕机,你肯定希望它一下子就宕机,不管子线程。那么此时你就可以把这些子线程设置为守护线程。

  • 相关阅读:
    hdu 3791 二叉搜索树
    hdu 4041 Eliminate Witches! 栈和队列
    后缀数组讲解
    Theme Section HDU
    Wow! Such Doge! HDU
    Girls' research HDU
    吉哥系列故事――完美队形II HDU
    Best Reward HDU
    String Problem HDU
    最大最小表示法
  • 原文地址:https://www.cnblogs.com/zhengna/p/10542017.html
Copyright © 2020-2023  润新知