zoukankan      html  css  js  c++  java
  • 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"线程结束")
    线程和线程池 整体的结构和思想差不多就结束了 其余变化的都是形式
    可以多试着写几遍 便能拨开云雾

    结束。


  • 相关阅读:
    如何发布自定义的UI 组件库到 npmjs.com 并且编写 UI组件说明文档
    Go 包导入备忘
    Incorrect column count: expected 1, actual 5,JdbcTemplate queryForList 出错
    SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装
    Java最快的maven仓库地址,国内Maven地址,超快的Maven地址
    SQLyog-12.4.2版下载,SQLyog最新版下载,SQLyog官网下载,SQLyog Download
    easyui datebox定位到某一个日期, easyui datebox直接定位到具体的日期, easyui datebox MoveTo方法使用
    Echarts调整图表上下左右的间距,Echarts调整柱状图左右的间距
    Spring整合Quartz定时任务执行2次,Spring定时任务执行2次
    Linux关闭Tomcat为什么要用Kill,而不是shutdown.sh
  • 原文地址:https://www.cnblogs.com/zhouA/p/15741518.html
Copyright © 2011-2022 走看看