线程池和进程池以及线程queue

线程queue

既然有进程的队列,那么也会有线程的queue

线程的queue有三种方式

并且导入模块的方式和进程不一样

先进先出

import queue
q = queue.Queue()#
q.put('123')
q.put('qweqwe')
print(q.get())
print(q.get())
# print(q.get())
q.task_done()
q.task_done()
q.join()

123
qweqwe

和之前的joinablequeue一样,这个需要用task_done来减掉计数器的值。不然join那里就会一直阻塞住。这是先进先出。

先进后出

q = queue.LifoQueue() #堆栈 先进后出
q.put('粉红色的背心儿')
q.put('粉红色的裤子')
q.put('欧文的各种设备')
print(q.get())
print(q.get())
print(q.get())
q.task_done()
q.task_done()
q.task_done()
q.join()

欧文的各种设备
粉红色的裤子
粉红色的背心儿

按照优先级

q = queue.PriorityQueue() # 可以根据优先级取数据
# 通常这个元组的第一个值是int类型
q.put((50,'ccc'))
q.put((80,'bbb'))
q.put((1,'aaa'))
print(q.get())
print(q.get())
print(q.get())
q.task_done()
q.task_done()
q.task_done()
q.join()

(1, 'aaa')
(50, 'ccc')
(80, 'bbb')

线程定时器

就是定时多久开启一个线程,并且不会阻塞住。

from threading import Thread,Timer
import time


def task():
    print('线程执行了')
    time.sleep(2)
    print('线程结束了')


t = Timer(4,task) # 过了4s后开启了一个线程
t.start()
print('qweqweqwe')

qweqweqwe
线程执行了
线程结束了

这里打印qweqweqwe没有被阻塞,而是直接就打印了,并没有等待4秒,因为不会阻塞,

这也是为什么有这个方法,而不用time.sleep的原因,因为sleep会阻塞住。

进程池和线程池

为什么要有进程池?进程池的概念。

在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。那么我们要怎么做呢?

在这里,要给大家介绍一个进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果

线程池也一样。

同步和异步的区别

同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码

异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time

def task(i):
    print(f'{currentThread().name} 在执行任务 {i}')
    # print(f'进程 {current_process().name} 在执行任务 {i}')
    time.sleep(1)
    return i**2

if __name__ == '__main__':
    pool = ThreadPoolExecutor(4) # 池子里只有4个线程
    # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
    fu_list = []
    for i in range(20):
        # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
        future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
        print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
        #fu_list.append(future)
    #pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
    #for fu in fu_list:
       #print(fu.result())

ThreadPoolExecutor-0_0 在执行任务 0
0
ThreadPoolExecutor-0_0 在执行任务 1
1
ThreadPoolExecutor-0_1 在执行任务 2
4
ThreadPoolExecutor-0_0 在执行任务 3
9
ThreadPoolExecutor-0_2 在执行任务 4
16
ThreadPoolExecutor-0_1 在执行任务 5
25
ThreadPoolExecutor-0_3 在执行任务 6
36
ThreadPoolExecutor-0_0 在执行任务 7
49
ThreadPoolExecutor-0_2 在执行任务 8
64
ThreadPoolExecutor-0_1 在执行任务 9
81
ThreadPoolExecutor-0_3 在执行任务 10
100
ThreadPoolExecutor-0_0 在执行任务 11
121
ThreadPoolExecutor-0_2 在执行任务 12
144
ThreadPoolExecutor-0_1 在执行任务 13
169
ThreadPoolExecutor-0_3 在执行任务 14
196
ThreadPoolExecutor-0_0 在执行任务 15
225
ThreadPoolExecutor-0_2 在执行任务 16
256
ThreadPoolExecutor-0_1 在执行任务 17
289
ThreadPoolExecutor-0_3 在执行任务 18
324
ThreadPoolExecutor-0_0 在执行任务 19
361

这就是同步了,因为你打印一定要等到他拿到这个result才能继续。

因此,改良了一下

'''
进程池线程池:
    池的功能限制进程数或线程数.
    什么时候限制?
    当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
    \我就应该考虑去限制我进程数或线程数,从保证服务器不崩.


'''


from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time

def task(i):
    print(f'{currentThread().name} 在执行任务 {i}')
    # print(f'进程 {current_process().name} 在执行任务 {i}')
    time.sleep(1)
    return i**2

if __name__ == '__main__':
    pool = ThreadPoolExecutor(4) # 池子里只有4个线程
    # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
    fu_list = []
    for i in range(20):
        # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
        future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
        # print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
        fu_list.append(future)
    pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
    for fu in fu_list:
        print(fu.result())



ThreadPoolExecutor-0_0 在执行任务 0
ThreadPoolExecutor-0_1 在执行任务 1
ThreadPoolExecutor-0_2 在执行任务 2
ThreadPoolExecutor-0_3 在执行任务 3
ThreadPoolExecutor-0_2 在执行任务 4
ThreadPoolExecutor-0_0 在执行任务 5
ThreadPoolExecutor-0_1 在执行任务 6
ThreadPoolExecutor-0_3 在执行任务 7
ThreadPoolExecutor-0_0 在执行任务 8
ThreadPoolExecutor-0_2 在执行任务 9
ThreadPoolExecutor-0_1 在执行任务 10
ThreadPoolExecutor-0_3 在执行任务 11
ThreadPoolExecutor-0_1 在执行任务 12
ThreadPoolExecutor-0_0 在执行任务 13
ThreadPoolExecutor-0_2 在执行任务 14
ThreadPoolExecutor-0_3 在执行任务 15
ThreadPoolExecutor-0_1 在执行任务 16
ThreadPoolExecutor-0_2 在执行任务 17
ThreadPoolExecutor-0_0 在执行任务 18
ThreadPoolExecutor-0_3 在执行任务 19
0
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
289
324
361

把所有的future都放进列表,然后列表一起拿结果。但是这样消耗的时间还是太多了。

于是就有了一个叫做回调函数的东西。

'''
进程池线程池:
    池的功能限制进程数或线程数.
    什么时候限制?
    当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
    \我就应该考虑去限制我进程数或线程数,从保证服务器不崩.


理解为提交任务的两种方式
同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码,


异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.


'''


from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time

def task(i):
    print(f'{currentThread().name} 在执行任务 {i}')
    # print(f'进程 {current_process().name} 在执行任务 {i}')
    time.sleep(1)
    return i**2


def parse(future):
    # 处理拿到的结果
    print(future.result())



if __name__ == '__main__':
    pool = ThreadPoolExecutor(4) # 池子里只有4个线程
    # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
    fu_list = []
    for i in range(20):#4
        # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
        future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
        future.add_done_callback(parse)
        # 为当前任务绑定了一个函数,在当前任务执行结束的时候会触发这个函数,
        # 会把future对象作为参数传给函数
        # 这个称之为回调函数,处理完了回来就调用这个函数.
        # print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行

    # pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
    # for fu in fu_list:
    #     print(fu.result())

ThreadPoolExecutor-0_0 在执行任务 0
ThreadPoolExecutor-0_1 在执行任务 1
ThreadPoolExecutor-0_2 在执行任务 2
ThreadPoolExecutor-0_3 在执行任务 3
0
ThreadPoolExecutor-0_0 在执行任务 4
1
ThreadPoolExecutor-0_1 在执行任务 5
4
ThreadPoolExecutor-0_2 在执行任务 6
9
ThreadPoolExecutor-0_3 在执行任务 7
16
ThreadPoolExecutor-0_0 在执行任务 8
25
ThreadPoolExecutor-0_1 在执行任务 9
36
ThreadPoolExecutor-0_2 在执行任务 10
49
ThreadPoolExecutor-0_3 在执行任务 11
64
ThreadPoolExecutor-0_0 在执行任务 12
100
81
ThreadPoolExecutor-0_1 在执行任务 13
ThreadPoolExecutor-0_2 在执行任务 14
121
ThreadPoolExecutor-0_3 在执行任务 15
144
ThreadPoolExecutor-0_0 在执行任务 16
196
169
ThreadPoolExecutor-0_2 在执行任务 17
ThreadPoolExecutor-0_1 在执行任务 18
225
ThreadPoolExecutor-0_3 在执行任务 19
256
324
289
361

这才是正确操作。

posted @ 2019-09-19 22:02  chanyuli  阅读(243)  评论(0编辑  收藏  举报