zoukankan      html  css  js  c++  java
  • 多任务线程基础与总结

    一、对线程的理解

     1.一个程序运行起来至少有一个进程,一个进程至少有一个线程
     2.处理器cpu分配给线程,即cpu真正运行的是线程中的代码
     3.分配cpu给线程时,是通过时间片轮训方式进行的
     4.进程是操作系统分配程序执行资源的单位,而线程是进程的一个实体,是CPU调度和分配的单位。

    二、python实现多线程的两种方式

     1、创建函数并且传入Thread 对象中
     
     示例如下:

    # 引入threading线程模块
        import threading
        import time
    
        def download_music():
            """模拟下载歌曲,需要5秒钟下载完成"""
                for i in range(5):
                time.sleep(1)  # 休眠1秒
                print("---正在下载歌曲%d---" % i)
    
        def play_music():
            """模拟播放歌曲,需要5秒钟下载完成"""
               for i in range(5):
                   time.sleep(1)  # 休眠1秒
                print("---正在播放歌曲%d---" % i)
    
        def main():
            # 创建线程对象t1
            # target: 指向新开启的线程要执行的代码
                t1 = threading.Thread(target=download_music)
                t2 = threading.Thread(target=play_music)
    
                t1.start()  # 启动线程,既然线程开始执行
                t2.start()
    
        if __name__ == '__main__':
           main()

    2.继承Thread类,创建一个新的class,将要执行的代码 写到run函数里面

    # 自定义类,继承threading.Thread
        class MyThread(threading.Thread):
                def run(self):
                    for i in range(5):
                        time.sleep(1)
                        # name属性中保存的是当前线程的名字
                       msg = "I'm " + self.name + ' @ ' + str(i)
                        print(msg)
    
    
        if __name__ == '__main__':
            # 通过MyThread创建线程对象
                t1 = MyThread()
    
            # 开始执行线程
                t1.start()

    三、线程何时开启,何时结束

     1.子线程何时开启,何时运行
         当调用thread.start()时 开启线程,再运行线程的代码

     2.子线程何时结束
         子线程把target指向的函数中的语句执行完毕后,或者线程中的run函数代码执行完毕后,立即结束当前子线程

     3.查看当前线程数量
         通过threading.enumerate()可枚举当前运行的所有线程

     4.主线程何时结束
         所有子线程执行完毕后,主线程才结束

    四、多线程(共享全局变量的问题)

     1.在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
     2.缺点就是,多线程对全局变量随意遂改可能造成全局变量的混乱(即线程非安全)
     3.如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确,即会遇到线程安全问题

    五、互斥锁

     1.当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制

     2.线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

     3.互斥锁为资源引入一个状态:锁定/非锁定

     4.某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

     5.hreading模块中定义了Lock类,可以方便的处理锁定:

    # 创建锁
    mutex = threading.Lock()
    
    # 锁定
    mutex.acquire()
    
    # 释放
    mutex.release()

    6.例如:使用互斥锁完成2个线程对同一个全局变量各加100万次的操作

        import threading
        import time
    
        g_num = 0
    
        def test1(num):
                global g_num
                for i in range(num):
                    mutex.acquire()  # 上锁
                    g_num += 1
                    mutex.release()  # 解锁
    
               print("---test1---g_num=%d"%g_num)
    
        def test2(num):
                global g_num
                    for i in range(num):
                    mutex.acquire()  # 上锁
                    g_num += 1
                    mutex.release()  # 解锁
    
                print("---test2---g_num=%d"%g_num)
    
        # 创建一个互斥锁
        # 默认是未上锁的状态
        mutex = threading.Lock()
    
        # 创建2个线程,让他们各自对g_num加1000000次
        p1 = threading.Thread(target=test1, args=(1000000,))
        p1.start()
    
        p2 = threading.Thread(target=test2, args=(1000000,))
        p2.start()
    
        # 等待计算完成
        while len(threading.enumerate()) != 1:
        time.sleep(1)
    
       print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)   

    加了互斥锁就不会出现资源竞争而导致结果与理想不合。

  • 相关阅读:
    AS3包类大全新手必学
    31天重构学习笔记27. 去除上帝类
    31天重构学习笔记26. 避免双重否定
    31天重构学习笔记29. 去除中间人对象
    与继承相关的一些重构(二)
    31天重构学习笔记28. 为布尔方法命名
    与继承相关的一些重构(一)
    31天重构学习笔记25. 引入契约式设计
    必会重构技巧(一):封装集合
    31天重构学习笔记30. 尽快返回
  • 原文地址:https://www.cnblogs.com/longguoliang/p/9347812.html
Copyright © 2011-2022 走看看