进程池与线程池

在介绍进程池和线程池之前,我们需要对其原理有一个了解。总所周知,进程和线程都是不可被重复利用的,在实现高并发中,这会极大的浪费资源。所以首先我们应该想办法实现线程和进程的可重复利用,而生产者与消费者模式就可以很好地解决这个问题。当我们需要开启多个线程或进程时,难道只能一个个去开吗?这时我们可以开辟一个进程池或线程池,可以一次就开启多个进程或线程,池的简单实现也可以用生产者与消费者模式来实现。最后在弄清楚基本实现原理,我们可以直接使用python自带的进程池和线程池。

可重复利用的线程池

利用生产者与消费者模式来实现线程的可重复利用,将主线程作为生产者,子线程作为消费者,让主线程调用来生产任务,子线程执行任务。

from threading import Thread
from queue import Queue

if __name__ == '__main__':
    class MyThread(Thread):
        def __init__(self,que):
            super().__init__()
            self.que = que
            self.daemon = True
            self.start()
        def run(self): #子线程执行 ,充当消费者
            while True:
                task = self.que.get()
                self.que.task_done()
                task() #执行任务
        def apply_async(self,func): #充当生产者,在主线程中调用
            self.que.put(func) #生产任务
        def join(self, timeout=None):
            self.que.join()
    def func1():
        print("这是任务1")
    def func2():
        print("这是任务2")
    que = Queue(10)
    T = MyThread(que)
    T.apply_async(func1)
    T.apply_async(func2)
    T.apply_async(func1)
    T.apply_async(func2)
    T.join() #等待队列结束
这是任务1
这是任务2
这是任务1
这是任务2

上述代码就是实现了一个线程重复执行多个任务,实现了线程的可重复利用。下面在上面代码加以改进,实现任务可传参。

from threading import Thread
from queue import Queue

if __name__ == '__main__':
    class MyThread(Thread):
        def __init__(self,que):
            super().__init__()
            self.que = que
            self.daemon = True
            self.start()
        def run(self): #子线程执行 ,充当消费者
            while True:
                task,args,kwargs = self.que.get()
                self.que.task_done()
                task(*args,**kwargs) #执行任务
        def apply_async(self,func,args = (),kwargs = {}): #充当生产者,在主线程中调用
            self.que.put((func,args,kwargs)) #生产任务
        def join(self, timeout=None):
            self.que.join()
    def func1(*args,**kwargs):
        print("这是任务1,代号是%d"%args)
        print(kwargs)
    def func2(*args,**kwargs):
        print("这是任务2,代号是%d"%args)
        print(kwargs)
    que = Queue(10)
    T = MyThread(que)
    T.apply_async(func1,args=(666,),kwargs={'name':'刘亦菲'})
    T.apply_async(func2,args=(888,),kwargs={'name':'胡歌'})
    T.apply_async(func1,args=(222,),kwargs={'name':'素素'})
    T.apply_async(func2,args=(111,),kwargs={'name':'龙'})
    T.join()
这是任务1,代号是666
{'name': '刘亦菲'}
这是任务2,代号是888
{'name': '胡歌'}
这是任务1,代号是222
{'name': '素素'}
这是任务2,代号是111
{'name': '龙'}

实现简单线程池

简单的线程池原理是让主线程充当生产者,只管向线程池提交任务,不管是哪个线程来执行,而线程池充当消费者,负责执行任务,将任务分配给空闲的子线程。

from threading import Thread
from queue import Queue

if __name__ == '__main__':
    class ThreadPool():
        def __init__(self,n):
            self.que = Queue()
            for i in range(n):
                Thread(target=self.func,args=(self.que,),daemon = True).start()
        def func(self,que):
            while True:
                task = que.get()
                self.que.task_done()
                task()
        def apply_async(self,task):
            self.que.put(task)
        def join(self):
            self.que.join()
    def func1():
        print("这是任务一")
    def func2():
        print("这是任务二")
    p = ThreadPool(5) #开启5个线程
    p.apply_async(func1)
    p.apply_async(func2)
    p.apply_async(func1)
    p.apply_async(func2)
    p.join()
这是任务一
这是任务二
这是任务一
这是任务二

python自带池

进程池和线程池创建用的是同一个模块(multiprocessing),但方法不同,进程池的方法是Pool,线程池的方法是pool.ThreadPool。不管是进程池还是线程池,它们都是默认开启守护模式的。下面以进程池为例:

  • 实例化:pool = Pool(num),num是开启进程的数量。
  • 提交任务:pool.apply_async(func[,args = (),kwds = {}])
  • 关闭:pool.close(),关闭后就禁止再提交任务。
  • join等待:pool.join(),只要队列计数器不为0,就一直阻塞。
  • 中止进程:pool.terminate():中止进程池,中止所有任务。

multiprocessing.cpu_count()可以返回cpu数

任务函数的返回值怎么获取?

通过变量接收:async_esult = pool.apply_async(func) ,再用get方法获取返回值:result = async_esult.get()。这个方法get会阻塞,又返回结果就解阻塞。

下面是利用线程池来实现简单的操作

from multiprocessing.pool import ThreadPool
if __name__ == '__main__':
    def func1(*args,**kwargs)
        print("这是任务一")
        return "hello"
    def func2(*args,**kwargs):
        print("这是任务二")
    p = ThreadPool(2)
    a = p.apply_async(func1) #获取任务返回值
    print(a.get())
    p.apply_async(func2)
    a = p.apply_async(func1) #获取任务返回值
    print(a.get())
    p.apply_async(func2)
    p.close()
    p.join()
这是任务一
hello
这是任务二
这是任务一
hello
这是任务二

使用池来实现并发服务器

from multiprocessing.pool import ThreadPool
import socket
if __name__ == '__main__':
    server = socket.socket()
    server.bind(('127.0.0.5',8899))
    server.listen(20)
    p = ThreadPool(20)
    def recv(coon,addr):
        while True:
            data = coon.recv(1024)
            if data:
                print("收到来自{}的信息:{}".format(addr,data.decode()))
                coon.send("已收到信息:%s"%data)
            else:
                coon.close()
                break
    while True:
        coon,addr = server.accept() #有一个连接过来就交给一个线程去执行
        p.apply_async(recv,args=(coon,addr))

 

 

 

posted @ 2018-11-01 19:14  龙~白  阅读(1608)  评论(0编辑  收藏  举报