zoukankan      html  css  js  c++  java
  • python 多线程, 多进程, 协程

    1. 介绍:

    threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。

    2. 1  线程执行函数

    #!/bin/python
    #coding:utf8
    
    import threading
    import time
    
    def action(arg):
        time.sleep(1)
        print "this ia arg %s 
    " % arg
    thread_list = []
    for i in xrange(4):
        t = threading.Thread(target=action,args=(i,))
        t.start()
        thread_list.append(t)
    
    for t in thread_list:
        t.join()
    
    print 'main end'
    # coding:utf-8
    
    import threading
    import time
    
    gl_num = 0
    
    lock = threading.RLock()
    
    
    # 调用acquire([timeout])时,线程将一直阻塞,
    # 直到获得锁定或者直到timeout秒后(timeout参数可选)。
    # 返回是否获得锁。
    def Func():
        lock.acquire()
        global gl_num
        gl_num += 1
        time.sleep(1)
        print gl_num
        lock.release()
    
    
    for i in range(10):
        t = threading.Thread(target=Func)
        t.start()


    在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
    缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

    2.2 线程继承类

    import threading
    import time
    
    class MyThread(threading.Thread):
        def __init__(self,arg):
            super(MyThread,self).__init__()
            self.arg = arg
    
        def run(self):
            time.sleep(1)
            print 'this arg is %s 
    ' % self.arg
    thread_list = []
    for i in xrange(4):
        t = MyThread(i)
        t.setDaemon(True)
        t.start()
        thread_list.append(t)
    
    for i in thread_list:
        t.join()
    
    
    print 'main end'

    3.介绍:

    构造方法: 
    Thread(group=None, target=None, name=None, args=(), kwargs={}) 

      group: 线程组,目前还没有实现,库引用中提示必须是None; 
      target: 要执行的方法; 
      name: 线程名; 
      args/kwargs: 要传入方法的参数。

    实例方法: 
      isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。 
      get/setName(name): 获取/设置线程名。 

      start():  线程准备就绪,等待CPU调度
      is/setDaemon(bool): 获取/设置是后台线程(默认前台线程(False))。(在start之前设置)

        如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止
             如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
      start(): 启动线程。 
      join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。

      join()阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout,即使设置了setDeamon(True)主线程依然要等待子线程结束。

    二、多进程

     multiprocessing
    python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。Python提供了非常好用的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

    1.1 函数

    import multiprocessing
    import time
    
    def worker(interval):
        n = 5
    
        while n > 0:
    
            print "this is  n=%d" % n
            time.sleep(interval)
            n -=1
    
    p = multiprocessing.Process(target=worker,args=(3,))
    m = multiprocessing.Process(target=worker,args=(4,))
    
    p.start()
    m.start()
    print m.pid
    print '-----------'
    print p.pid
    print p.name
    print p.is_alive()
    print multiprocessing.active_children() # 获取所有的进程
    print 'main end'

    1.2 类

    import multiprocessing
    import time
    
    class ClockProcess(multiprocessing.Process):
        def __init__(self, interval):
            multiprocessing.Process.__init__(self)
            self.interval = interval
    
        def run(self):
            n = 5
            while n > 0:
                print("the time is {0}".format(time.ctime()))
                time.sleep(self.interval)
                n -= 1
    
    if __name__ == '__main__':
        p = ClockProcess(3)
        p.start()    
    p.daemon = True
    因子进程设置了daemon属性,主进程结束,它们就随着结束了,# 默认是false
    2. Lock 锁
    当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突。
    import multiprocessing
    import sys
    
    def worker_with(lock, f):
        with lock:
            fs = open(f, 'a+')
            n = 10
            while n > 1:
                fs.write("Lockd acquired via with
    ")
                n -= 1
            fs.close()
            
    def worker_no_with(lock, f):
        lock.acquire()
        try:
            fs = open(f, 'a+')
            n = 10
            while n > 1:
                fs.write("Lock acquired directly
    ")
                n -= 1
            fs.close()
        finally:
            lock.release()
        
    if __name__ == "__main__":
        lock = multiprocessing.Lock()
        f = "file.txt"
        w = multiprocessing.Process(target = worker_with, args=(lock, f))
        nw = multiprocessing.Process(target = worker_no_with, args=(lock, f))
        w.start()
        nw.start()
        print "end"

     

    3.Event用来实现进程间同步通信。

    import multiprocessing
    import time
    
    def worker(e):
         print "worker start"
         e.wait()
         print ("workder e.is_set()" +str(e.is_set()))
    
    
    def worker_for(e,t):
        print "worker_for start"
        e.wait(t)
    
        print "worker)for is_set" + str(e.is_set())
    
    
    e = multiprocessing.Event()
    w1 = multiprocessing.Process(target=worker,args=(e,))
    w2 = multiprocessing.Process(target=worker_for,args=(e,4))
    
    w1.start()
    w2.start()
    
    time.sleep(3)
    e.set()
    print "mail"

    4.Queue

    Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
     
    get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常。Queue的一段示例代码:
    def writer_proc(q):
        try:
            q.put("this a ")
            print "put"
        except Exception as e:
            print e
    
    def reader_proc(q):
        try:
            print "get"
            print q.get()
        except Exception as e:
            print e
            print '1111'
            pass
    
    q = multiprocessing.Queue()
    writer = multiprocessing.Process(target=writer_proc,args=(q,))
    writer.start()
    
    reader = multiprocessing.Process(target=reader_proc,args=(q,))
    
    reader.start()
    
    #writer.join()
    #reader.join()

    5. Pipe

    Pipe方法返回(conn1, conn2)代表一个管道的两个端。Pipe方法有duplex参数,如果duplex参数为True(默认值),那么这个管道是全双工模式,也就是说conn1和conn2均可收发。duplex为False,conn1只负责接受消息,conn2只负责发送消息。
     
    send和recv方法分别是发送和接受消息的方法。例如,在全双工模式下,可以调用conn1.send发送消息,conn1.recv接收消息。如果没有消息可接收,recv方法会一直阻塞。如果管道已经被关闭,那么recv方法会抛出EOFError。
    import multiprocessing
    import time
    
    def proc1(pipe):
        while True:
            for i in xrange(1000):
                print "send : %d" % i
                pipe.send(i)
                time.sleep(1)
    
    def proc2(pipe):
        while True:
            print "proc2 sev:", pipe.recv()
            time.sleep(2)
    
    def proc3(pipe):
        while True:
            print "Proc3 rev:" , pipe.recv()
            time.sleep(1)
    pipe = multiprocessing.Pipe()
    print pipe
    p1 = multiprocessing.Process(target=proc1,args=(pipe[0],))
    p2 = multiprocessing.Process(target=proc2,args=(pipe[1],))
    #p3 = multiprocessing.Process(target=proc3,args=(pipe[1],))
    p1.start()
    p2.start()
    #p3.start()
    p1.join()
    p2.join()
    #p3.join()

     6. Pool

    在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
    Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

    函数解释:

    • apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞,apply(func[, args[, kwds]])是阻塞的(理解区别,看例1例2结果区别)
    • close()    关闭pool,使其不在接受新的任务。
    • terminate()    结束工作进程,不在处理未完成的任务。
    • join()    主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用。

    执行说明:创建一个进程池pool,并设定进程的数量为3,xrange(4)会相继产生四个对象[0, 1, 2, 4],四个对象被提交到pool中,因pool指定进程数为3,所以0、1、2会直接送到进程中执行,当其中一个执行完事后才空出一个进程处理对象3,所以会出现输出“msg: hello 3”出现在"end"后。因为为非阻塞,主函数会自己执行自个的,不搭理进程的执行,所以运行完for循环后直接输出“mMsg: hark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~”,主程序在pool.join()处等待各个进程的结束。

    三、协程

    1. greenlet实现协程

      Python的 greenlet就相当于手动切换,去执行别的子程序,在“别的子程序”中又主动切换回来。。。

    from greenlet import greenlet
    
    def test1():
        print 123
        gr2.switch()
        print 456
        gr2.switch()
    
    def test2():
        print "abc"
        gr1.switch()
        print "def"
    
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    
    gr1.switch()

    2. gevent 实现协程

      Gevent 是一个第三方库,可以轻松通过gevent实现协程程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

      gevent会主动识别程序内部的IO操作,当子程序遇到IO后,切换到别的子程序。如果所有的子程序都进入IO,则阻塞。

    参考资料:https://www.cnblogs.com/tkqasn/p/5700281.html

    https://www.cnblogs.com/kaituorensheng/p/4445418.html (多进程)

    https://www.cnblogs.com/zingp/p/5911537.html (协程)

  • 相关阅读:
    java中split函数参数特殊字符的处理(转义),如:"." 、"\"、"|"
    Javascript编程风格
    HTTP 错误 500.0的解决方法。
    在WCF中进行大数据量传输
    “您已使用临时配置文件登陆”的解决方法
    关于命令行执行Migrations
    转一篇关于部署的文章
    MSDeploy使用备忘
    不可征服
    git初始化项目
  • 原文地址:https://www.cnblogs.com/myvic/p/9812614.html
Copyright © 2011-2022 走看看