zoukankan      html  css  js  c++  java
  • python多任务-线程

    多任务的概念

    什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。

    现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?

    答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。

    真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

    注意:

    • 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
    • 并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的

    线程基础

    python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用

    单线程执行

    import time
    
    
    def test():
            print("test...")
            time.sleep(1)
    
    
    if __name__ == '__main__':
    
            for i in range(5):
                    test()
    
    

    执行效果:程序在控制台每隔一秒打印test...

    多线程执行

    import time
    import threading
    
    def test():
            print("test...")
            time.sleep(1)
    
    
    if __name__ == '__main__':
    
            for i in range(5):
                    t = threading.Thread(target=test)
                    t.start() # 启动线程
        
    

    执行效果:程序在控制台一下子输出五行test...,等待1秒左右结束

    说明:

    1. 可以明显看出使用了多线程并发的操作,花费时间要短很多
    2. 当调用start()时,才会真正的创建线程,并且开始执行

    主线程会等待所有子线程结束后才结束

    import time
    import threading
    
    
    def playPhone():
    
            print('玩手机...')
            time.sleep(1)
    
    
    def eat():
    
            print("吃东西...")
            time.sleep(1)
    
    
    if __name__ == '__main__':
    
            print("--开始--")
    
            t1 = threading.Thread(target=playPhone)
            t1.start()
    
            t2 = threading.Thread(target=eat)
            t2.start()
    
            print('--执行结束')
    
    

    执行效果:主线程阻塞1秒左右后程序结束,说明主线程在等待其他线程执行完毕。

    查看线程数量

              print('玩手机...')
                    time.sleep(1)
    
    
    def eat():
    
            for i in range(10):
                    print("吃东西...")
                    time.sleep(1)
    
    
    if __name__ == '__main__':
    
            print("--开始--")
    
            t1 = threading.Thread(target=playPhone)
            t1.start()
    
            t2 = threading.Thread(target=eat)
            t2.start()
        
            # 查看正在执行的线程数量
            while True:
                    length = len(threading.enumerate())
                    print("当前运行的线程数量:%d" % length)
                    print("这些线程是:%s" % str(threading.enumerate()))
        
        
                    if length == 1:
                            break
        
                    time.sleep(0.5)    
    
            print('--执行结束')
    

    在python中,调用threading.enumerate()能获取当前正在运行的所有线程,返回值是一个list,调用length()函数并传入该list对象就获取到当前运行线程的数量。

    线程-注意点

    线程执行代码的封装

    通过上一篇,能够看出,通过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法。

    示例如下:

    import time
    import threading
    
    
    class MyThread(threading.Thread):
    
            def run(self):
                    for i in range(5):
                            time.sleep(1)
                            print("我是%s@%d" % (self.name, i)) 
    
    
    if __name__ == "__main__":
            mt = MyThread()
            mt.start()
    

    运行结果如下:

    我是Thread-1@0
    我是Thread-1@1
    我是Thread-1@2
    我是Thread-1@3
    我是Thread-1@4
    

    python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。

    线程的执行顺序

    mport time
    import threading
    
    
    class MyThread(threading.Thread):
    
            def run(self):
                    for i in range(5):
                            time.sleep(1)
                            print("我是%s@%d" % (self.name, i)) 
    
    
    if __name__ == "__main__":
        
            for i in range(5):
                    mt = MyThread()
                    mt.start()
    

    执行结果(运行的结果可能不一样,但是大体是一致的):

    我是Thread-5@0
    我是Thread-2@0
    我是Thread-3@0
    我是Thread-4@0
    我是Thread-1@0
    我是Thread-3@1
    我是Thread-4@1
    我是Thread-2@1
    我是Thread-5@1
    我是Thread-1@1
    我是Thread-3@2
    我是Thread-4@2
    我是Thread-2@2
    我是Thread-5@2
    我是Thread-1@2
    我是Thread-3@3
    我是Thread-4@3
    我是Thread-2@3
    我是Thread-5@3
    我是Thread-1@3
    我是Thread-3@4
    我是Thread-4@4
    我是Thread-5@4
    我是Thread-2@4
    我是Thread-1@4
    

    从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。

    总结

    1. 每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的name,但是python会自动为线程指定一个名字。
    2. 当线程的run()方法结束时该线程完成。
    3. 无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。
  • 相关阅读:
    unittest模块小结
    自定义日志类
    配置文件的简单操作
    自动化框架搭建(一)
    openpyxl一点心得
    关于过滤字符中不同元素小结
    关于传入列表出现元素次数排序题目的一点心得
    Python中*和**的作用(课堂小结)
    Python代码的人机大战(循环嵌套)
    最后期限阅读笔记02
  • 原文地址:https://www.cnblogs.com/zhangfengxian/p/python-thread.html
Copyright © 2011-2022 走看看