zoukankan      html  css  js  c++  java
  • Python中多进程的使用

    • 进程:程序的一次执行(程序载入内存,系统分配资源运行)。每个进程有自己的内存空间,数据栈等,进程之间可以进行通讯,但是不能共享信息。
    • 线程:所有的线程运行在同一个进程中,共享相同的运行环境。每个独立的线程有一个程序入口,顺序执行序列和程序的出口。
    • 线程的运行可以被强占,中断或者暂时被挂起(睡眠),让其他的线程运行。一个进程中的各个线程共享同一片数据空间。

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

    多线程比较适合IO密集型,不太适合CPU密集型的任务。

    #queue 多线程各个线程的运算的值放到一个队列中,到主线程的时候再拿出来,以此来代替
    #return的功能,因为在线程是不能返回一个值的
    import time
    import threading
    from Queue import Queue
     
    def job(l,q):
        q.put([i**2 for i in l])
         
    def multithreading(data):
        q = Queue()
        threads = []
        for i in xrange(4):
            t = threading.Thread(target = job,args = (data[i],q))
            t.start()
            threads.append(t)
        for thread in threads:
            thread.join()
        results = []
        for _ in range(4):
            results.append(q.get())
        print results
             
    if __name__ == "__main__":
        data = [[1,2,3],[4,5,6],[3,4,3],[5,5,5]]
        multithreading(data)
     
    [[1, 4, 9], [16, 25, 36], [9, 16, 9], [25, 25, 25]]

    全局解释器锁GIL(Global Interpreter Lock)

    GIL并不是Python的特性,他是CPython引入的概念,是一个全局排他锁。

    解释执行python代码时,会限制线程对共享资源的访问,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL。
     
    所以,虽然CPython的线程库直接封装了系统的原生线程,但CPython整体作为一个进程,同一时间只会有一个获得GIL的线程在跑,其他线程则处于等待状态。这就造成了即使在多核CPU中,多线程也只是做着分时切换而已,所以多线程比较适合IO密集型,不太适合CPU密集型的任务。同一时刻一个解释进程只有一行bytecode 在执行

    多进程

    multiprocessing库弥补了thread库因为GIL而低效的缺陷。完整的复制了一套thread所提供的接口方便迁移,唯一的不同就是他使用了多进程而不是多线程。每个进程都有自己独立的GIL。但是在windows下多进程的开销要比多线程要大好多,Linux下是差不多的。多进程更加稳定;

    创建函数并将其作为单个进程

    import multiprocessing
    import time
    
    def worker(interval):
        n = 5
        while n > 0:
            print("The time is {0}".format(time.ctime()))
            time.sleep(interval)
            n -= 1
    
    if __name__ == "__main__":
        p = multiprocessing.Process(target = worker, args = (3,))
        p.start()
        print "p.pid:", p.pid
        print "p.name:", p.name
        print "p.is_alive:", p.is_alive()

    - 使用线程池

    # 进程池 ,Pool中是有return的
    import multiprocessing as mp
    
    def job(x):
        return x ** 2
    
    def multiprocess():
        pool = mp.Pool()  # 默认是有几个核就用几个,可以自己设置processes = ?
        res = pool.map(job, range(10))  # 可以放入可迭代对象,自动分配进程
        print(res)
    # apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞,apply(func[, args[, kwds]])是阻塞的 res
    = pool.apply_async(job, (2,)) # 一次只能在一个进程里计算,要达到map的效果,要迭代 print(res.get()) multi_res = [pool.apply_async(job, (i,)) for i in range(10)] # 迭代器 print([res.get() for res in multi_res]) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # 4 # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

    - fork操作:调用一次,返回两次。操作系统自动把当前进程复制一份,分布在父进程和子进程中返回,子进程永远返回0,父进程永远返回子进程的ID。子进程getppid()就可以拿到父进程的ID;

  • 相关阅读:
    MYsql增删改查
    粘包问题
    模拟ssh远程执行命令
    Socket抽象层
    基于TCP协议的socket套接字编程
    TCP协议的三次握手和四次挥手
    大话OSI七层协议
    网络架构及其演变过程
    互联网和互联网的组成
    Windows安装MySQL
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/10219134.html
Copyright © 2011-2022 走看看