zoukankan      html  css  js  c++  java
  • 第24课 多线程开发

    一、多线程开发


    1、进程和线程

      1、进程的概念:运行着的程序。比如,windows下的任务管理器,里面就是各种程序的进程。

      2、线程的概念:

        1---每个进程里面至少包含一个线程

        2---线程是操作系统创建的,用来控制代码执行的数据结构

        3---线程就像代码执行的许可证

        4---单线程程序,主线程的入口就是代码的开头

        5---主线程顺序往下执行,直到所有的代码都执行完

    2、概念对应:通过银行办理业务来解释程序运行的相关概念

      1、一个服务窗口 ==CPU的一个核

      2、客户 == 进程(运行着的程序)

      3、调度员 == 操作系统

      4、服务号 == 线程

      5、调度员分配服务号给客户 == OS分配线程给进程代码

      6、服务窗口给客户办理业务 == CPU核心执行线程代码

    3、线程库:

      1、代码通过系统调用,请求OS分配一个新的线程

      2、python里面,thread和threading都可以用来创建和管理线程

      3、thread比较底层---thread只有在python2中使用,python3已停用

      4、threading是thread模块的扩展,提供了很多线程同步功能,使用起来更加方便强大

    4、我们为什么需要多线程 :

       1、多线程给一个程序并并行执行代码的能力----同时处理多个任务

        $convert

        >>convert 1.avi

        >>convert 2.avi

      2、常见的

        1、UI线程

        2、任务线程 task  exeute

    5、多线程使用共享数据

      1、共享对象的概念,比如常见的自动取款机

        1---某个时刻只能一个人使用

        2---进入后往往会锁上门(表示已经被使用)

        3---看到里面有人,外面的人排队等待

        4---用完后开锁(表示已经取钱结束)

        5---后一个排队的人进去取钱(重复这个过程)

      2、共享数据使用场景实例

        1---YY用户支付宝账号的余额为2000元

        2---他乘坐滴滴打车要扣钱

        3---他的余额宝会给他挣钱

        4---处理滴滴打车的逻辑在线程#1里执行

        5---处理余额宝挣钱的逻辑在线程#2里执行

        6---今天,他坐滴滴打车扣了10块钱,假设余额宝挣的钱也是10块

      3、共享数据需要用线程锁,否则可能导致数据出错。

    6、条件变量-----比较难懂,工作中遇到再研究吧

      

    二、知识点补充

    1、if __name__ == __'main__' 的使用

      1、有时候我们导入一个模块后,只是想使用这个模块的特定函数功能,并不想执行这个模块里面的测试代码,这时候可以使用if  __name__ ==  "__main__"方法

    实例 :m1里面有测试代码,m2调用m1模块时,并不想执行m1里面的测试代码,这时候该怎么办?

    #  m1模块
    
    def sayHello():
        print('hello')
    
    def sayGoodbye():
        print('goodbye')
    
    # 测试代码  testing code
    
    print('exec testing')
    sayHello()
    sayGoodbye()

    m2调用m1模块,m1模块内的测试代码也被执行

    # m2调用m1模块
    
    import m1
    
    m1.sayHello()
    
    
    # 执行结果:
    
    D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/m2.py"
    exec testing
    hello
    goodbye
    hello
    
    Process finished with exit code 0

    m3中,入口模块是__main__,则执行m3中的测试代码。

    def sayHello():
        print('hello')
    
    def sayGoodbye():
        print('goodbye')
        
    print(f'm3 name is ' + __name__)   # 打印m3的入口代码
    
    if __name__ == '__main__':  # 如果入口代码是__main__,则执行测试代码
        print('exec testing')
        sayHello()
        sayGoodbye()
    
    
    # 执行结果
    
    D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/m3.py"
    m3 name is __main__
    exec testing
    hello
    goodbye
    
    Process finished with exit code 0

    m4导入m3模块,这时候执行m4时,先执行m3里面的打印语句:print(f  'm3 name is'  +  __name__),因为m3是被引用的,这时候它的入口函数在m4里面已经变成了m3,

    所以,m3里面的测试代码就不会被执行。然后再执行print(__name__),最后执行m3.sayHello()。

    # m4
    
    import m3   # 导入m3模块,这时候执行m3里面的print(f'm3 name is ' + __name__)语句,其它函数不调用不执行
    
    print(__name__)  #打印m4的入口函数名称
     
    m3.sayHello()  # 调用m3的sayHello函数
    
    
    # 执行结果
    D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/m4.py"
    m3 name is m3
    __main__
    hello
    
    Process finished with exit code 0

    实例

    3-1     t1 = threading.Thread(target = thread1_entry)  ,threading是python的一个库,Thread是threading里面的类。

         target 后面跟的是函数对象,不是函数里面的返回值,所以不能写成target = thread1_entry(), thread1_entry称为入口函数

         t1只是创建了一个线程,但是并未开始执行,需要执行t1.start(),才会执行新的线程。就是执行入口函数thread1_entry里面的内容

     1 print('main thread start 1!')
     2 
     3 import threading
     4 from time import sleep
     5 
     6 def threda1_entry():
     7     print('child thread 1, start')
     8     sleep(15)
     9     print('child thread 1,  end')
    10 
    11 t1 = threading.Thread(target = thread1_entry)   # target:对象的意思,后面跟的是函数对象,不是对象的返回值   # Thread是threading模块的类
    12 t1.start()
    13 t1.sleep(10)
    14 print(main thread end)
    15 
    16 
    17 执行结果:
    18 D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/lesson57 知识点.py"
    19 main thread start!
    20 child thread 1, start
    21 child thread 1, end
    22 main thread end
    23 
    24 Process finished with exit code 0

    4-1

     1 from time import sleep, ctime
     2 
     3 def thread1_entry(nsec):
     4     print('child thread 1, start at:', ctime())
     5     sleep(nsec)
     6     print('child thread 2, start at:', ctime())
     7 
     8 print('main thread start.')
     9 
    10 def thread2_entry(nsec):
    11     print('child thread 1, end.', ctime())
    12     sleep(esec)
    13     print('child ehread 2, end.',  ctime())
    14 
    15 # 创建线程对象,指定了新的入口函数
    16 t1 = threading.Thread(target = thread1_entry, args = (1,))
    17 t2 = threading.Thread(target = thread2_entry, args = (2,))
    18 
    19 # 启动新线程
    20 t1.start()
    21 t2.start()
    22 
    23 # t1线程结束
    24 t1.join()
    25 
    26 # t2线程结束
    27 t2.join()
    28 print('main thread end.')
    29 
    30 
    31 
    32 # 执行结果
    33 
    34 D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/lesson57 知识点.py"
    35 main thread start.
    36 child thread 1, start at: Fri Jul 10 15:30:22 2020
    37 child thread 2, start at: Fri Jul 10 15:30:22 2020
    38 child thread 1, end at: Fri Jul 10 15:30:23 2020
    39 child thread 2, end at: Fri Jul 10 15:30:24 2020
    40 main thread end.
    41 
    42 Process finished with exit code 0

    5-1 多线程使用共享数据

     1 import threading
     2 from time import sleep
     3 
     4 def thread_entry():
     5 
     6     # 注意,局部变量var的值,同时被两个线程调用,会搞混乱吗?
     7     var = 1
     8     for i in range(10):
     9         # threading.currentThread().ident  获取当前线程的ID号
    10         print('th #{}:{}'.format(threading.currentThread().ident, var))
    11         sleep(1)
    12         var += 1
    13 
    14 
    15 print('main thread start.')
    16 
    17 t1 = threading.Thread(target=thread_entry)
    18 t2 = threading.Thread(target=thread_entry)
    19 
    20 
    21 t1.start()
    22 t2.start()
    23 
    24 t1.join()
    25 t2.join()
    26 
    27 print('main thread end.')
    28 
    29 
    30 # 执行结果:
    31 D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/lesson57 知识点.py"
    32 main thread start.
    33 th #8788:1
    34 th #7524:1
    35 th #8788:2th #7524:2
    36 
    37 th #7524:3th #8788:3
    38 
    39 th #8788:4th #7524:4
    40 
    41 th #7524:5
    42 th #8788:5
    43 th #8788:6th #7524:6
    44 
    45 th #8788:7
    46 th #7524:7
    47 th #7524:8
    48 th #8788:8
    49 th #8788:9
    50 th #7524:9
    51 th #8788:10th #7524:10
    52 
    53 main thread end.
    54 
    55 Process finished with exit code 0

    5-2-2   共享数据出现的问题,结果跟预期不符

    import threading
    from time import sleep
    
    zhifubao = {
        'YY' : 2000,
        'dabao' : 50000,
        'liming' : 6005000
        }
    
    # 线程1 :滴滴打车处理,参数是用户账户扣款金额
    
    def thread1_didi_pay(account, amount):
        print('t1: get balance from bank')
        balance = zhifubao[account]
    
    
        # 下面的sleep(2)表示一些处理过程需要花上2秒钟
        print('* t1: do something(like discount lookup) for 2 second')
        sleep(2)
    
        print('* t1: deduct')
        zhifubao[account] = balance - amount
    
    
    # 线程2:余额宝处理,参数是用户账户和当前利息
    def thread2_yuebao_interest(account, amount):
        print('$ t2: get balance from bank')
        balance = zhifubao[account]
    
        # 下面的sleep(1)表示一些处理过程需要花上1秒钟
        print('$ t2: do something2 ...for 1 seconds')
        sleep(1)
    
        print('$ t2: add')
        zhifubao[account] = balance + amount
    
    
    
    t1 = threading.Thread(target= thread1_didi_pay, args=('YY', 10))
    t2 = threading.Thread(target= thread2_yuebao_interest, args=('YY', 10))
    
    
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    
    print('finally, YY balance is %s' % zhifubao['YY'])
    
    
    
    执行结果:
    
    D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/lesson57 知识点.py"
    t1: get balance from bank
    * t1: do something(like discount lookup) for 2 second
    $ t2: get balance from bank
    $ t2: do something2 ...for 1 seconds
    $ t2: add
    * t1: deduct
    finally, YY balance is 1990
    
    Process finished with exit code 0

    5-3-1  使用线程锁,避免共享数据出错

     1 import threading
     2 from time import sleep
     3 
     4 
     5 zhifubao = {
     6     'YY' : 2000,
     7     'lming' : 365000,
     8     'zhaolei' : 6005000
     9     }
    10 
    11 
    12 
    13 # 调用一个lock函数,返回一个锁对象
    14 zhifubao_lock = threading.Lock()
    15 
    16 
    17 def thread1_didi_pay(account, amount):
    18     # 在代码访问共享对象之前,加锁
    19     # 当多个线程同时执行lock.acquire时,只有一个线程能成功获取锁,然后继续执行代码
    20     # 其他线程继续等待,直到获得锁为止
    21     zhifubao_lock.acquire()
    22     print('* t1: get balance from bank')
    23     balance = zhifubao[account]
    24 
    25     print('* t1: do something(like discount lookup) for 2 seconds')
    26     sleep(2)
    27 
    28 
    29     print('*t1: deduct')
    30     zhifubao[account] = balance - amount
    31 
    32 
    33     # 访问完共享对象后,释放锁
    34     # 访问结束后,一定要调用lock对象的acquire方法,进行解锁操作
    35     # 否则其它等待锁的线程将永远等待下去,成为死线程
    36     zhifubao_lock.release()
    37 
    38 
    39 def thread2_yuebao_interest(account, amount):
    40     # 在代码访问共享对象之前,加锁
    41     zhifubao_lock.acquire()
    42     print('$ t2: get balance from bank')
    43     balance = zhifubao[account]
    44 
    45     print('$ t2: do something2...for 1 seconds')
    46     sleep(1)
    47 
    48     print('$ t2: add')
    49     zhifubao[account] = balance + amount
    50     zhifubao_lock.release()
    51 
    52 t1 = threading.Thread(target=thread1_didi_pay, args=('YY', 2000))
    53 t2 = threading.Thread(target=thread2_yuebao_interest, args=('YY', 2000))
    54 
    55 t1.start()
    56 t2.start()
    57 t1.join()
    58 t2.join()
    59 
    60 print('finally, YY balance is %s:' % zhifubao['YY'])
    61 
    62 
    63 
    64 # 执行结果
    65 
    66 D:Pythonpython.exe "D:/Programs/HelloWorld2/songqin/python/lesson57 多线程/lesson57 知识点.py"
    67 * t1: get balance from bank
    68 * t1: do something(like discount lookup) for 2 seconds
    69 *t1: deduct
    70 $ t2: get balance from bank
    71 $ t2: do something2...for 1 seconds
    72 $ t2: add
    73 finally, YY balance is 2000:
    74 
    75 Process finished with exit code 0
  • 相关阅读:
    PHP获取当前页面完整url地址,包括参数的函数
    研究在SAE上搭建最新wordpress
    CentOS6.5 编译安装lnmp环境
    cried me a river--kristinia debarge
    Bad Day -- Daniel Powter
    Back to December -- Taylor Swift
    英语单词的偏旁部首之常见前缀(一)
    21 Guns -- Green Day
    影子
    BNUOJ 1037 精神控制
  • 原文地址:https://www.cnblogs.com/nick1998/p/13270141.html
Copyright © 2011-2022 走看看