返回顶部
首页 > 资讯 > 后端开发 > Python >进程池、线程池、回调函数、协程
  • 568
分享到

进程池、线程池、回调函数、协程

线程回调函数 2023-01-31 00:01:48 568人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

摘要: 进程池与线程池 同步调用和异步调用 回调函数 协程 一、进程池与线程池: 1、池的概念:   不管是线程还是进程,都不能无限制的开下去,总会消耗和占用资源。   也就是说,硬件的承载能力是有限度的,在保证高效率工作的同时应该还

摘要:

  • 进程池与线程池
  • 同步调用和异步调用
  • 回调函数
  • 协程

一、进程池与线程池:

1、池的概念:

  不管是线程还是进程,都不能无限制的开下去,总会消耗和占用资源。

  也就是说,硬件的承载能力是有限度的,在保证高效率工作的同时应该还需要保证硬件的资源占用情况,所以需要给硬件设置一个上限来减轻硬件的压力,所以就有了池的概念。

2、进程池与线程池的使用方法:(进程与线程的创建基本相似,所以进程池与线程池的使用过程也基本一样)

from concurrent.futures import ProcessPoolExecutor  # 导入进程池模块
from concurrent.futures import ThreadPoolExecutor # 导入线程池模块
import os
import time
import random

# 下面以进程池为例,线程池只是使用导入模块不一样,仅此而已。
def task(name):
    print('name:[%s]|进程:[%s]正在运行' % (name, os.getpid()))
    time.sleep(random.randint(1, 3))   # 模拟进程运行耗费时间。

# 这一步的必要性:在创建进程时,会将代码以模块的方式从头到尾导入加载执行一遍
# (所以创建线程如果不写在main里面的话,这个py文件里面的所有代码都会从头到尾加载执行一遍
# 就会导致在创建进程的时候产生死循环。)
if __name__ == '__main__':
    pool = ProcessPoolExecutor(4)  # 设置线程池的大小,默认等于cpu的核心数。
    for i in range(10):
        pool.submit(task, '进程%s' % i)  # 异步提交(提交后不等待)
    
    pool.shutdown(wait=True)  # 关闭进程池入口不再提交,同时等待进程池全部运行完毕。(类似join方法)
    print('主') # 标识一下主进程的完毕之前的语句
# 运行过程及结果:
name:[进程0]|进程:[4080]正在运行
name:[进程1]|进程:[18336]正在运行
name:[进程2]|进程:[19864]正在运行
name:[进程3]|进程:[25604]正在运行
name:[进程4]|进程:[4080]正在运行
name:[进程5]|进程:[18336]正在运行
name:[进程6]|进程:[4080]正在运行
name:[进程7]|进程:[19864]正在运行
name:[进程8]|进程:[25604]正在运行
name:[进程9]|进程:[18336]正在运行
主
运行结果

 二、同步调用、异步调用

  同步调用:提交任务,原地等待该任务执行完毕,拿到结果后再执行下一个任务,导致程序串行执行!

from concurrent.futures import ProcessPoolExecutor  # 导入进程池模块
from concurrent.futures import ThreadPoolExecutor # 导入线程池模块
import os
import time
import random


def task(name):
    print('name:[%s]|进程[%s]正在运行...' % (name, os.getpid()))
    time.sleep(random.randint(1, 3))
    return '拿到[%s]|进程%s的结果...' % (name, os.getpid())

if __name__ == '__main__':
    pool = ProcessPoolExecutor(4)
    result = []  # 创建一个空列表来搜集执行结果
    for i in range(10):
        res = pool.submit(task, '进程%s' % i).result()  # 使用.result()方法得到每次的结果,同步调用
        result.append(res)
    pool.shutdown(wait=True)
    for j in result:
        print(j)
    print('主进程')

 

# 执行结果:
name:[进程0]|进程[3376]正在运行...
name:[进程1]|进程[27124]正在运行...
name:[进程2]|进程[10176]正在运行...
name:[进程3]|进程[28636]正在运行...
name:[进程4]|进程[3376]正在运行...
name:[进程5]|进程[27124]正在运行...
name:[进程6]|进程[10176]正在运行...
name:[进程7]|进程[28636]正在运行...
name:[进程8]|进程[3376]正在运行...
name:[进程9]|进程[27124]正在运行...
拿到[进程0]|进程3376的结果...
拿到[进程1]|进程27124的结果...
拿到[进程2]|进程10176的结果...
拿到[进程3]|进程28636的结果...
拿到[进程4]|进程3376的结果...
拿到[进程5]|进程27124的结果...
拿到[进程6]|进程10176的结果...
拿到[进程7]|进程28636的结果...
拿到[进程8]|进程3376的结果...
拿到[进程9]|进程27124的结果...
主进程
过程和结果

 

  异步调用:提交任务,不去等结果,继续执行。

from concurrent.futures import ProcessPoolExecutor
import os
import random
import time

def task(name):
    time.sleep(random.randint(1, 3))
    print('name: %s 进程[%s]运行...' % (name, os.getpid()))


if __name__ == '__main__':
    pool = ProcessPoolExecutor(4)
    for i in range(10):
        pool.submit(task, '进程%s' % i)   # 异步调用,提交后不等待结果,继续执行代码

    pool.shutdown(wait=True)
    print('主进程')
name: 进程3 进程[10016]运行...
name: 进程0 进程[12736]运行...
name: 进程1 进程[4488]运行...
name: 进程2 进程[3920]运行...
name: 进程5 进程[12736]运行...
name: 进程6 进程[4488]运行...
name: 进程4 进程[10016]运行...
name: 进程9 进程[4488]运行...
name: 进程8 进程[12736]运行...
name: 进程7 进程[3920]运行...
主进程
过程和结果

 三、回调函数:

  上面我们在演示异步调用时候,说过提交任务不等待执行结果,继续往下执行代码,那么,执行的结果我们怎么得到呢?

  可以为进程池和线程池内的每个进程或线程绑定一个函数,该函数在进程或线程的任务执行完毕后自动触发并接收任务的返回值当做参数,这个函数就是回调函数。
from concurrent.futures import ThreadPoolExecutor
import time
import random
import requests


def task(url):
    print('获取网站[%s]信息' % url)
    response = requests.get(url)  # 下载页面
    time.sleep(random.randint(1, 3))
    return {'url': url, 'content': response.text}  # 返回结果:页面地址和页面内容

futures = []
def back(res):
    res = res.result()  # 取到提交任务的结果(回调函数固定写法)
    res = '网站[%s]内容长度:%s' % (res.get('url'), len(res.get('content')))
    futures.append(res)
    return futures

if __name__ == '__main__':
    urls = [
        'Http://www.baidu.com',
        'http://www.dgtle.com/',
        'https://www.bilibili.com/'
    ]
    pool = ThreadPoolExecutor(4)
    futures = []
    for i in urls:
        pool.submit(task, i).add_done_callback(back)  # 执行完线程后,使用回调函数

    pool.shutdown(wait=True)
    for j in futures:
        print(j)
获取网站[http://www.baidu.com]信息
获取网站[http://www.dgtle.com/]信息
获取网站[https://www.bilibili.com/]信息
网站[http://www.dgtle.com/]内容长度:39360
网站[https://www.bilibili.com/]内容长度:69377
网站[http://www.baidu.com]内容长度:2381
结果

 四:协程(通过单线程实现并发

我们知道,多个线程执行任务时候,如果其中一个任务遇到io操作系统会有一种来回'切'的机制,来最大效率利用cpu的使用效率,从而实现多线程并发效果

而协程:就是用单线程实现并发,通过软件代码手段,在代码执行过程中遇到IO,自动切换到进程中的另外一个执行的代码,然后再次遇到IO,继续切换到另一个

执行的代码。

过程就是:单进程中任务执行中:遇到IO,代码层面在单线程中切换代码执行。从而骗过操作系统,让操作系统以为这个单线程好像没经历过IO,从而达到该

单线程对cpu使用的效率最大化。

实现过程所需模块:gevent 

from gevent import monkey; monkey.patch_all()  # 监测代码中所有IO行为
# gevent模块不能识别它本身以外的所有的IO行为,但是它内部封装了一个模块,能够帮助我们识别所有的IO行为
from gevent import spawn # 从gevent模块导入spawn,来使用‘切’的方法 import time import random def heng(name): print('%s 哼了一下...' % name) time.sleep(random.randint(1, 3)) print('%s 哼完了' % name) def ha(name): print('%s 哈了一下' % name) time.sleep(random.randint(1, 3)) print('%s 哈完了' % name) start = time.time() # 标记开始时间 s1 = spawn(heng, '王大锤') # 标记并运行heng函数(遇到IO,切) s2 = spawn(ha, '至尊宝') # 标记并运行ha函数(遇到IO,切) s1.join() s2.join() # s1、s2都执行完毕后才继续执行 print('运行时间:', time.time()-start)

 

王大锤 哼了一下...
至尊宝 哈了一下
王大锤 哼完了
至尊宝 哈完了
运行时间: 2.0049164295196533
结果

 

  进程:资源单位
     线程:执行单位
  协程:单线程下实现并发(能够在多个任务之间切换和保存状态来节省IO),这里注意区分操作系统的切换+保存状态是针对多个线程而言,而我们现在是想在单个线程下自己手动实现操作系统的切换+保存状态的功能

注意协程这个概念完全是程序员自己想出来的东西,它对于操作系统来说根本不存在。操作系统只知道进程和线程。并且需要注意的是并不是单个线程下实现切换+保存状态就能提升效率,因为你可能是没有遇到io也切,那反而会降低效率

再回过头来想上面的Socket服务端实现并发的例子,单个线程服务端在建立连接的时候无法去干通信的活,在干通信的时候也无法去干连接的活。这两者肯定都会有IO,如果能够实现通信io了我就去干建连接,建连接io了我就去干通信,那其实我们就可以实现单线程下实现并发

将单个线程的效率提升到最高,多进程下开多线程,多线程下用协程>>> 实现高并发!!!

协程实现服务端客户端通信

# 服务端:
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import socket
n = 0

def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:break
            print(data.decode('utf-8'))
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()


def server(): # 切点
    global n
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        # n += 1
        spawn(communicate, conn)    # 切点
        # print(n)

if __name__ == '__main__':
    s1 = spawn(server)
    s1.join()
# 客户端
from threading import Thread,current_thread
import socket


def client():

    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    n = 1
    while True:
        data = '%s %s'%(current_thread().name, n)
        n += 1
        client.send(data.encode('utf-8'))
        info = client.recv(1024)
        print(info)

if __name__ == '__main__':
    for i in range(500):  # 多线程模拟多客户的访问服务器,进行通信循环。
        t = Thread(target=client)
        t.start()

# 原本服务端需要开启500个线程才能跟500个客户端通信,现在只需要一个线程就可以扛住500客户端
# 进程下面开多个线程,线程下面再开多个协程,最大化提升软件运行效率

 






--结束END--

本文标题: 进程池、线程池、回调函数、协程

本文链接: https://lsjlt.com/news/182562.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 进程池、线程池、回调函数、协程
    摘要: 进程池与线程池 同步调用和异步调用 回调函数 协程 一、进程池与线程池: 1、池的概念:   不管是线程还是进程,都不能无限制的开下去,总会消耗和占用资源。   也就是说,硬件的承载能力是有限度的,在保证高效率工作的同时应该还...
    99+
    2023-01-31
    线程 回调 函数
  • Python Django 协程报错,进程池、线程池与异步调用、回调机制
    在Django视图函数中,导入 gevent 模块import gevent from gevent import monkey; monkey.patch_all() ...
    99+
    2023-01-31
    报错 线程 回调
  • python线程池回调函数怎么使用
    在Python中,可以使用`concurrent.futures`模块中的`ThreadPoolExecutor`来创建线程池,并利...
    99+
    2023-10-26
    python
  • Python并发编程之线程池/进程池
    原文来自开源中国前言python标准库提供线程和多处理模块来编写相应的多线程/多进程代码,但当项目达到一定规模时,频繁地创建/销毁进程或线程是非常消耗资源的,此时我们必须编写自己的线程池/进程池来交换时间空间。但是从Python3.2开始,...
    99+
    2023-06-02
  • golang线程池和协程池有什么区别
    Golang中没有线程池的概念,而是通过协程(goroutine)来实现并发。协程是一种轻量级的线程,由Go语言的运行时环境(run...
    99+
    2023-10-26
    golang
  • python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池
    目录1、ThreadPoolExecutor多线程<1>为什么需要线程池呢<2>标准库concurrent.futures模块<3>简单使用<...
    99+
    2024-04-02
  • Java手写线程池之向JDK线程池进发
    目录前言JDK线程池一瞥自己动手实现线程池线程池参数介绍实现Runnable实现Callable拒绝策略的实现线程池关闭实现工作线程的工作实现线程池实现的BUG完整代码线程池测试总结...
    99+
    2022-11-13
    Java手写线程池 Java线程池
  • 关于java连接池/线程池/内存池/进程池等汇总分析
    目录一、引言二、池技术的由来和目的三、池技术的原理四、池技术的优缺点对象池:内存池:线程池:数据库连接池:连接池:进程池:缓冲池:工作队列:六、延伸与拓展缓存(Caching):延迟...
    99+
    2023-05-16
    java池技术 java连接池 java线程池 java内存池 java进程池
  • 进程池
        from multiprocessing import Pool import os import time def worker(num): print("task <%s> is runing <...
    99+
    2023-01-30
    进程
  • Python自带的线程池和进程池有什么用
    这篇文章主要介绍“Python自带的线程池和进程池有什么用”,在日常操作中,相信很多人在Python自带的线程池和进程池有什么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2024-04-02
  • python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池怎么使用
    这篇文章主要介绍了python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python中ThreadPoolE...
    99+
    2023-07-02
  • 线程池之newFixedThreadPool定长线程池的实例
    newFixedThreadPool定长线程池的实例 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。newFixedThr...
    99+
    2024-04-02
  • SpringBoot线程池和Java线程池怎么使用
    这篇文章主要介绍“SpringBoot线程池和Java线程池怎么使用”,在日常操作中,相信很多人在SpringBoot线程池和Java线程池怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringB...
    99+
    2023-07-06
  • python3--队列Queue,管道Pipe,进程之间的数据共享,进程池Pool,回调函数callback
    进程multiprocessProcess —— 进程 在python中创建一个进程的模块  start  daemon 守护进程  join 等待子进程执行结束锁 Lockacquire release锁是一...
    99+
    2023-01-30
    进程 队列 回调
  • golang要协程池吗
    golang不需要协程池。具体原因:1、Golang的协程是非常轻量级的,其创建和销毁的成本非常低;2、Golang的通道机制提供了安全、高效的任务传递方式,可以限制并发任务的数量,使得不需要额外的协程池来管理并发;3、Golang运行时包...
    99+
    2023-07-18
  • 线程池之newCachedThreadPool可缓存线程池的实例
    java线程池: Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,...
    99+
    2024-04-02
  • 线程池是什么?线程池(ThreadPoolExecutor)使用详解
    点一点,了解更多https://www.csdn.net/ 本篇文章将详细讲解什么是线程池,线程池的参数介绍,线程池的工作流程,使用Executors创建常见的线程池~~~ 目录 点一点,了解更多 文章目录 一、线程池的概念 1.1线...
    99+
    2023-09-03
    java 数据结构 jvm 面试 java-ee
  • 怎么使用Node实现轻量化进程池和线程池
    今天小编给大家分享一下怎么使用Node实现轻量化进程池和线程池的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们...
    99+
    2024-04-02
  • Android中线程池
    一、线程池的优点 说到线程池的优点就要先说一下不用线程池的坏处 在早些年开发都是直接new Thread()直接创建线程,倘若有N个异步就要创建N个线程,这会导致线程的频繁创建和销毁线程不可控,每个线程都各自执行,内存资源竞争激烈,这可能会...
    99+
    2023-09-17
    android java
  • 线程池类型
    线程池按功能分的话有: 1、FixedThreadPool(定长线程池):只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结果的有界队列,控制线程的最大并发数 2、ScheduledThreadPool(定时线程池):核心线程...
    99+
    2023-09-11
    java Powered by 金山文档
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作