14.效率利器之多线程和线程池

单线程和多线程:

怎么来理解线程?在这里举个通俗的例子,便于记忆。

一张圆桌上面有十碗饭,假如一个人吃一碗饭的时间为1min,那么吃完这一桌需要10min

(这里一个人我们将他认为成一个线程)

假如我设定五个人同时开始吃这桌饭,那么吃完这一桌需要大约为1*2=2min

假如我设定十个人同时开始吃这桌饭,那么吃完这一桌需要大约为1min

这里为什么多线程的时候会加上大约 这里会涉及到资源抢夺的问题 暂且不管。

通过上面的例子,我们了解多线程能大大的提高程序的效率。

那么在代码中怎么实现呢?

首先我们要了解Python中队列的用法:

队列的三种实现方法有:

      1、FIFO先入先出队列(Queue)

      2、LIFO后入先出队列(LifoQueue)

      3、优先级队列(PriorityQueue)

这里用到的是Queue

import queue   q = queue.Queue()  /  from queue import Queue   q = Queue()

q.qsize()  # 返回当前队列包含的消息数量
q.empty()  # 如果队列为空返回True 反之False
q.full()  # 如果队列满了,返回True 反之False
q.get()  # 获取队列,timeout等待时间  get(self, block=True,timeout=None) block表示是否等待 timeout表示等待多久
q.put(item)  # 写入队列 put(self, item, block=True,timeout=None) block表示是否等待 timeout表示等待多久
q.get_nowait()  # 相当于q.get(False) 获取不等待
q.put_nowait()  # 相当于 q.put(item,False) 写入不等待
q.task_done()  # 在完成一项工作之后,使用这个方法可以向队列发送一个信号,表示该任务执行完毕
q.join()  # 等待队列中所有任务(数据)执行完毕之后再往下执行,否则一直等待
注意点 :join是判断的依据。不单单指的是队列中没有数据,数据get出去之后,要使用task_done向队列发送一个信号,表示该任务执行完毕
/数据使用完毕

接下来我们要清楚线程的个数 怎么来设置的 并且里面的参数如何传递。

from threading import Thread
from queue import Queue
q = Queue()

def GetData(q,index):
    # 判断队列是否为空,空则退出while循环
    while q.empty() is False:
        # 打印信息
        print('next:' + str(q.qsize()) + 'index:'+str(index))
        # 将米饭从队列里拿出来
        rice = q.get()

        # 之后就可以对这100碗米饭进行五个线程的处理了
        # 比如:requests请求...


        # 表明该线程完成 发出个成功的消息
        q.task_done()
# 1 - 100 一共100碗米饭放到这个队列里去
for rice in range(1,101):
    q.put(rice)

# 遍历循环5次 代表设置5个线程
for index in range(5):
    """
    target目标  为线程要去做什么事情?
      args参数  需要传递的参数
    """
    # 这里目标 设置成一个函数
    # 将整个队列作为参数 和 线程的下标 传进去
    thread = Thread(target=GetData, args=(q,index,))
    # 不设置为守护线程
    thread.setDaemon(False)
    # 线程开始
    thread.start()
    
# 等待队列中所有任务(数据)执行完毕之后再往下执行,否则一直等待
q.join()

线程池的用法:

其实与多线程的目的一致,都是为了实现同样的结果,只是路子不一样罢了。

我们看看线程池的用法:

from concurrent.futures import ThreadPoolExecutor, as_completed

def handle_true(j):
    print(j)
    pass

# 创建一个线程池 它的工作量为10 即10个线程
threadpool = ThreadPoolExecutor(max_workers=10)

future_list = []
# 相同的100碗米饭
for j in range(1,101):
    # 这里注意 for 10次之后,10个线程任务分配完成。
    # for第11次开始的时候,是上10个线程中的某一个结束的时候
    # 以此类推
    future = threadpool.submit(handle_true,j)
    future_list.append(future)
# 阻塞器的功能,等待线程任务结束,不然就一直阻塞。
for future in as_completed(future_list):
    data_list_fin = future.result()  # 线程运行结果
    print('ERROR:', future.exception())  # 查看线程的异常,没有返回None
    print(f"线程结束")
线程和线程池 整体的结构和思想差不多就结束了 其余变化的都是形式
可以多试着写几遍 便能拨开云雾

结束。


原文地址:https://www.cnblogs.com/zhouA/p/15741518.html