• python之多线程


    声明:示例来源《python核心编程》

    前言

      单线程处理多个外部输入源的任务只能使用I/O多路复用,如:select,poll,epoll。

      特别值得注意的是:由于一个串行程序需要从每个 I/O 终端通道来检查用户的输入,程序在读取 I/O 终端通道时不能阻塞,因为用户输入的到达时间是不确定的,并且阻塞会妨碍其他 I/O 通道的处理。

      select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现只负责把数据从内核拷贝到用户空间。

    为此就引出了我们的主体多线程,多线程的特点:

    1. 本质上是异步的
    2. 需要多个并发活动
    3. 每个活动的处理顺序可能是不确定的,或者说是随机的、不可预测的。

    什么是进程?
    进程就是一个执行中的程序。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。操作系统管理其上所有进程的执行,并为这些进程合理地分配时间。进程也可以通过派生( fork 或 spawn)新的进程来执行其他任务,不过因为每个新进程也都拥有自己的内存和数据栈等,所以只能采用进程间通信( IPC)的方式共享信息。

    什么是线程?
    线程(有时候称为轻量级进程)与进程类似,不过它们是在同一个进程下执行的,并共享相同的上下文。可以将它们认为是在一个主进程或“主线程”中并行运行的一些“迷你进程”。

    python中的多线程实现

    threading模块中的对象列表

    ps:我们通过python实现多线程编程,主要用到的是threading.Thread对象

    Thread对象常用属性和方法

    多线程示例

    context: python2.7.13

    python通过Thread对象创建一个多线程实例,主要有3种方式:

    1. 创建 Thread 的实例,传给它一个函数。
    2. 创建 Thread 的实例,传给它一个可调用的类实例。
    3. 派生 Thread 的子类,并创建子类的实例。

    ps:我们通常会选择第一个或第三个方案。当你需要一个更加符合面向对象的接口时,会选择后者。所以,建议使用第三种方案,它是最适合你的应用和未来扩展的方法

    示例1:创建 Thread 的实例,传给它一个函数。

     1 #!/usr/bin/env python
     2 #-*- coding:utf-8 -*-
     3 import threading
     4 from time import sleep,ctime
     5 
     6 loops = [4,2]
     7 
     8 def loop(nloop,nsec):
     9     print "start loop",nloop,"at:",ctime()
    10     sleep(nsec)
    11     print "loop",nloop,'done at:',ctime()
    12 
    13 def main():
    14     print "Starting at:",ctime()
    15     threads = []
    16     nloops = range(len(loops))
    17     #完成所有线程分配,并不立即开始执行
    18     for i in nloops:
    19         t = threading.Thread(target=loop,args=(i,loops[i]))
    20         threads.append(t)
    21     #开始调用start方法,同时开始所有线程
    22     for i in nloops:
    23         threads[i].start()
    24     #join方法:主线程等待所有子线程执行完成,再执行主线程接下来的操作。
    25     for i in nloops:
    26         threads[i].join()
    27 
    28     print "All done at:",ctime()
    29 if __name__=="__main__":
    30     main()
    Starting at: Sun Jun 18 10:00:49 2017
    start loop 0 at: Sun Jun 18 10:00:49 2017
    start loop 1 at: Sun Jun 18 10:00:49 2017
    loop 1 done at: Sun Jun 18 10:00:51 2017
    loop 0 done at: Sun Jun 18 10:00:53 2017
    All done at: Sun Jun 18 10:00:53 2017
    
    Process finished with exit code 0
    resault

    示例2:创建 Thread 的实例,传给它一个可调用的类实例

    #!/usr/bin/env python
    #-*- encoding:utf-8 -*-
    import threading
    from time import sleep,ctime
    
    loops = [4,2]
    class ThreadFunc(object):
        def __init__(self,func,args,name=""):
            self.name = name
            self.func = func
            self.args = args
        #使类具有函数行为,就像函数的代理(proxy)
        def __call__(self):
            self.func(*self.args)
    
    def loop(nloop,nsec):
        print "start loop",nloop,"at:",ctime()
        sleep(nsec)
        print "loop",nloop,'done at:',ctime()
    
    def main():
        print "Starting at:",ctime()
        threads = []
        nloops = range(len(loops))
        #完成所有线程分配,并不立即开始执行
        for i in nloops:
            t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
            threads.append(t)
        #开始调用start方法,同时开始所有线程
        for i in nloops:
            threads[i].start()
        #join方法等待子线程执行完成,再执行主线程接下来的操作。
        for i in nloops:
            threads[i].join()
    
        print "All done at:",ctime()
    if __name__=="__main__":
        main()
    传入类实例
    Starting at: Sun Jun 18 10:03:52 2017
    start loop 0 at: Sun Jun 18 10:03:52 2017
    start loop 1 at: Sun Jun 18 10:03:52 2017
    loop 1 done at: Sun Jun 18 10:03:54 2017
    loop 0 done at: Sun Jun 18 10:03:56 2017
    All done at: Sun Jun 18 10:03:56 2017
    
    Process finished with exit code 0
    resault

    示例3:派生 Thread 的子类,并创建子类的实例。

    自定义类MyThread

    1. 文件名:mythread.py,
    2. 内容:MyThread为threading.Thread的派生类
    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    import threading
    from time import sleep,ctime
    
    class MyThread(threading.Thread):
        def __init__(self,func,args,name=""):
            threading.Thread.__init__(self)
            self.name = name
            self.func = func
            self.args = args
    
        def get_res(self):
            return self.res
    
        def run(self):
            print "Starting",self.name,"at:",ctime()
            self.res = self.func(*self.args)
            print self.name,"finish at:",ctime()

    菲波那切数列,阶乘,累加单线程也多线程对比

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    #MyThread为自定义的threading.Thread的派生类
    from mythread import MyThread
    from time import sleep,ctime
    #斐波那契数列
    def fib(x):
        sleep(0.005)
        if x < 2:return 1
        return (fib(x-2)+fib(x-1))
    #阶乘
    def fac(x):
        sleep(0.1)
        if x < 2:return 1
        return (x*fac(x-1))
    #累加
    def sum(x):
        sleep(0.1)
        if x < 2:return 1
        return (x + sum(x-1))
    funcs = [fib,fac,sum]
    n = 12
    def main():
        nfuncs = range(len(funcs))
        print "---SINGLE THREAD---"
        for i in nfuncs:
            print "Starting",funcs[i].__name__,"at:",ctime()
            print funcs[i](n)
            print funcs[i].__name__,"finish at:",ctime()
    
        print "
    ---MULTIPLE THREADS---"
        threads = []
        for i in nfuncs:
            t = MyThread(funcs[i],(n,),funcs[i].__name__)
            threads.append(t)
        for i in nfuncs:
            threads[i].start()
    
        for i in nfuncs:
            threads[i].join()
            print threads[i].get_res()
    
        print "All Done!"
    
    if __name__ == '__main__':
        main()
    ---SINGLE THREAD---
    Starting fib at: Sun Jun 18 09:12:17 2017
    233
    fib finish at: Sun Jun 18 09:12:24 2017
    Starting fac at: Sun Jun 18 09:12:24 2017
    479001600
    fac finish at: Sun Jun 18 09:12:26 2017
    Starting sum at: Sun Jun 18 09:12:26 2017
    78
    sum finish at: Sun Jun 18 09:12:27 2017
    
    ---MULTIPLE THREADS---
    Starting fib at: Sun Jun 18 09:12:27 2017
    Starting fac at: Sun Jun 18 09:12:27 2017
    Starting sum at: Sun Jun 18 09:12:27 2017
    fac finish at: Sun Jun 18 09:12:28 2017
    sum finish at: Sun Jun 18 09:12:28 2017
    fib finish at: Sun Jun 18 09:12:34 2017
    233
    479001600
    78
    All Done!
    
    Process finished with exit code 0
    resault

      以单线程模式运行时,只是简单地依次调用每个函数,并在函数执行结束后立即显示相应的结果。

      而以多线程模式运行时,并不会立即显示结果。 因为我们希望让 MyThread 类越通用越好(有输出和没有输出的调用都能够执行),我们要一直等到所有线程都执行结束,然后调用get_res()方法来最终显示每个函数的返回值。

  • 相关阅读:
    JAVA-基础-接口
    JAVA-基础-抽象类
    JAVA-基础-多态
    JAVA-基础-继承
    JAVA-基础-封装
    JAVA-基础-面向对象
    JAVA-基础-ArrayList集合
    CenOS 6.5下 mysql自动备份
    Cenos 6.5上的subverion的yum配置笔记
    [CF628D]Magic Numbers 题解
  • 原文地址:https://www.cnblogs.com/chbo/p/7043660.html
Copyright © 2020-2023  润新知