• python的进程与线程(二)


    线程

            之前了解了操作系统的发展史,也知道了进程和线程的概念,归纳一下就是:

            进程:本质上就是一段程序的运行过程(抽象的概念)

            线程:最小的执行单元,是进程的实体

            进程:最小的资源单位
     

    线程的调用

            在python中,一般通过导入threading模块来调用线程。 threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,提供了更方便的api来处理线程,先看一段直接调用的代码:

           直接调用:     

    # -*- coding: utf-8 -*-
    import threading,time
    
    def func1(n):
        print('传给我的是%s'%n)
        time.sleep(3)
    
    def func2():
        print('我没有参数的')
        time.sleep(5)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=func1,args=(5,))   #target传入的是函数名,不带括号,args要以元组形式传入参数
        t2 = threading.Thread(target=func2)   #没有参数就不用传
    
        t1.start()    #运行线程,本质是调用run方法
        t2.start()
        print('ending......')
        
    >>>传给我的是5
    >>>我没有参数的
    >>>ending......
    View Code

            运行的时候几乎同时打印了三条结果,然后等待约5s再停止,如果是单线程的话就要8s的时间才能运行完,这样做提升了效率。其次这个程序一共有多少线程呢?答案是3个,除了t1和t2两个实例化得到的子线程,还有程序本身的主线程,还记得那句话吗?一个程序至少有一个进程,一个进程至少有一个线程。

            继承方式调用线程: 

    import time
    import threading
    
    class Mythread(threading.Thread):
        def __init__(self,n):
            threading.Thread.__init__(self)
            self.n = n
    
        def func1(self):
            print('传给我的是%s'%self.n)
            time.sleep(self.n)
    
        def run(self):   ##定义每个线程要运行的函数
            self.func1()
    
    if __name__ == '__main__':
        t1 = Mythread(2)
        t2 = Mythread(5)
    
        t1.start()
        t2.start()
    
    >>>传给我的是2
    >>>传给我的是5
    View Code

           也是直接打印两条结果,然后等待5s程序结束。一般这种方式很少用到,都是直接调用比较快。如果不穿参数的话,__init__方法可以不用写,但是run函数一定要写的,至于为什么,你可以通过找继承的父类去推,这里就不啰嗦了。

           线程的join方法

         join是线程实例化后也具有的方法,像上边的start一样,那么join有什么作用呢?

    import threading
    from time import ctime,sleep
    
    def music(name):
    
            print ("Begin listening to %s. %s" %(name,ctime()))
            sleep(2)
            print("end listening %s"%ctime())
    
    
    def moive(title):
    
            print ("Begin recording the %s! %s" %(title,ctime()))
            sleep(5)
            print('end recording %s'%ctime())
    
    threads = []
    
    t1 = threading.Thread(target=ListenMusic,args=('毛不易的歌',))
    t2 = threading.Thread(target=RecordBlog,args=('白蛇',))
    
    threads.append(t1)
    threads.append(t2)
    
    if __name__ == '__main__':
    
        for t in threads:
            t.start()
            #t.join()#串行
        # t.join()
    
        # t1.join()
    
        # t2.join()########分别试一下这几种join位置下的结果
        print('endtime is %s'%ctime())
    View Code

          我们逐个分析,不加join时:

    Begin listening to 毛不易的歌. Thu Apr 11 17:47:01 2019
    Begin recording the 白蛇! Thu Apr 11 17:47:01 2019
    endtime is Thu Apr 11 17:47:01 2019
    end listening Thu Apr 11 17:47:04 2019
    end recording Thu Apr 11 17:47:06 2019

           加上一个t1.join时:

    Begin listening to 毛不易的歌. Thu Apr 11 17:49:42 2019
    Begin recording the 白蛇! Thu Apr 11 17:49:42 2019
    end listening Thu Apr 11 17:49:45 2019
    endtime is Thu Apr 11 17:49:45 2019
    end recording Thu Apr 11 17:49:47 2019

           注意endtime的变化,然后去试试其他情况就可以知道(注意for循环里面和外面的t的区别),join作用就是在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

           线程的setDaemon方法

          通过join我们可以阻塞线程,那么setDaemon就刚好相反,就是将线程声明为守护线程,但是必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦

    import threading
    from time import ctime,sleep
    
    def music(name):
    
            print ("Begin listening to %s. %s" %(name,ctime()))
            sleep(2)
            print("end listening %s"%ctime())
    
    
    def moive(title):
    
            print ("Begin recording the %s! %s" %(title,ctime()))
            sleep(5)
            print('end recording %s'%ctime())
    
    threads = []
    
    t1 = threading.Thread(target=ListenMusic,args=('毛不易的歌',))
    t2 = threading.Thread(target=RecordBlog,args=('白蛇',))
    
    threads.append(t1)
    threads.append(t2)
    
    if __name__ == '__main__':
        #t1.setDaemon(True)
        t2.setDaemon(True)
        for t in threads:
            #t.setDaemon(True)   #一定要在start前
            t.start()
            #t.join()#串行
        # t.join()
    
        t1.join()
    
        # t2.join()########分别试一下这几种join位置下的结果
        print('endtime is %s'%ctime())
    View Code

            看一下结果,白蛇没看完就停了

    Begin listening to 毛不易的歌. Thu Apr 11 18:03:42 2019
    Begin recording the 白蛇! Thu Apr 11 18:03:42 2019
    end listening Thu Apr 11 18:03:45 2019
    endtime is Thu Apr 11 18:03:45 2019

           其他方法

    # run():  线程被cpu调度后自动执行线程对象的run方法
    # start():启动线程活动。
    # isAlive(): 返回线程是否活动的。
    # getName(): 返回线程名。
    # setName(): 设置线程名。
    
    threading模块提供的一些方法:
    # threading.currentThread(): 返回当前的线程变量。
    # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

           基本的线程就是这样使用的,后面讲的就是同步和异步的概念,还有各种锁,慢慢来。

     

      

  • 相关阅读:
    手动配置linux(centos)的IP地址
    linux(centos)上配置nginx、mysql、phpfpm开机启动
    visual studio 2022 下载地址
    自己动手开发编译器(五)miniSharp语言的词法分析器
    自己动手开发编译器(一)编译器的模块化工程
    自己动手开发编译器(二)正则语言和正则表达式
    趣味问题:你能用Reflection.Emit生成这段代码吗?
    自己动手开发编译器(零)序言
    自己动手开发编译器特别篇——用词法分析器解决背诵圣经问题
    自己动手开发编译器(三)有穷自动机
  • 原文地址:https://www.cnblogs.com/pengfy/p/10691131.html
Copyright © 2020-2023  润新知