进程池(multiprocess.Pool)

2023-05-16

进程池(multiprocess.Pool)

一、进程池概念

1.什么是进程池?

  • 👉进程池是资源进程, 管理进程组成的技术的应用.

2.为什么要有进程池?

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

3.进程池的概念

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

4.资源进程

  • 👉预先创建好的空闲进程,管理进程(好比池子🏊)会把工作分发到空闲进程来处理。

5.管理进程🏊

  • 👉管理进程负责创建资源进程,把工作交给空闲资源进程处理,回收已经处理完工作的资源进程。

  • 资源进程与管理进程的交互

😱管理进程如何有效的管理资源进程,分配任务给资源进程?
👉通过IPC,信号,信号量,消息队列,管道等进行交互。

二.进程池的使用

我们可以通过维护一个进程池来控制进程的数目, 比如使用httpd的进程模式, 可以规定最大进程数和最小进程数, multiprocessing模块Pool类可以提供指定数量的进程供用户调用

1.创建一个进程池

  • 方法 : Pool([numprocess],[initializer],[initargs])
  • ps : 在多线程那篇文章中介绍另一种创建进程池方式 from concurrent.future import ProcessPoolExecutor
  • 参数
参数作用
numprocess要创建的进程数,如果省略,将默认使用cpu_count()的值
initializer每个工作进程启动时要执行的可调用对象,默认为None
initargs传给initializer的参数组

2.常用方法介绍

方法作用
p.apply(func,args,kwargs)(同步调用)在进程池工作的进程中执行func函数,后面是参数,然后返回结果,如果想要传入不同的参数并发的执行func, 就需要以不同的线程去调用p.apply()函数或者使用p.apply_async()
p.apply_async(func,args,kwargs)(异步调用)在进程池工作的进程中执行func函数,后面是参数,然后返回结果, 结果是AsyncResult类的实例, 可以使用回调函数callback, 将前面funct返回的结果单做参数传给回调函数
p.close( )关闭进程池,防止进一步操作, 如果所有操作持续挂起,它们将在工作进程终止前完成
P.jion()等待所有工作进程退出。此方法只能在close()或teminate()之后调用,否则报错

3.其他方法

以下方法运用于 pply_async()map_async()的返回值, 返回值是**AsyncResul **实例的对象, 也就是该对象的方法

方法作用
obj.get( )返回结果,如果有必要则等待结果到达。timeout是可选的。如果在指定时间内还没有到达,将引发一场。如果远程操作中引发了异常,它将在调用此方法时再次被引发
obj.ready( )如果调用完成,返回True
obj.successful( )如果调用完成且没有引发异常,返回True,如果在结果就绪之前调用此方法,引发异常
obj.wait([timeout])等待结果变为可用, 参数是超时时间
obj.terminate( )立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作。如果对象被垃圾回收, 将自动调用这个方法

4.同步调用示例 (apply)

from multiprocessing import Pool
import time,os,random
def test(n):
    print(f"子进程:{os.getpid()}")
    time.sleep(2)
    return n*random.randint(2,9)

if __name__ == '__main__':
    n = os.cpu_count()     # 本机CPU个数,我的是4,进程池容量个数自定义,默认CPU核数
    p = Pool(processes=n)  # 设置进程池进程个数,从无到有,并且以后一直只有这四个进程在执行任务
    li = []
    start_time = time.time()
    for i in range(10):
        res = p.apply(test,args=(2,))  # 创建十个个任务, 使用同步调用的方式
        li.append(res)
    p.close()  # 先关闭进程池, 不会再有新的进程加入到pool中, 防止进一步的操作(同步调用可以不加此方法)
    p.join()   # 必须在close调用之后执行, 否则报错, 执行后等待所有子进程结束(同步调用可以不加此方法)
    print(li)  # 同步调用, 得到的就是最终结果,(异步调用得到的是对象, 需要使用get方法取值)
    print(f'使用时间:{time.time()-start_time}')
    
'''输出
子进程:7768
子进程:16276
子进程:17544
子进程:15680
子进程:7768
子进程:16276
子进程:17544
子进程:15680
子进程:7768
子进程:16276
[4, 18, 14, 14, 12, 14, 16, 14, 6, 10]
使用时间:20.226498126983643
'''

从上面的输出结果可以看到,进程一直是那四个 : 7769、16276、17544、15680, 并且异步提交需要等待上一个任务结束拿到结果才能进行下一个任务, 所以用时 20 秒多一点

5.异步调用示例 (apply_async)

from multiprocessing import Pool
import time,os,random

def test(n):
    print(f"子进程:{os.getpid()}")
    time.sleep(2)
    return n*n*random.randint(2,9)

if __name__ == '__main__':
    n = os.cpu_count()     # 本机CPU个数,我的是4,进程池容量个数自定义,默认CPU核数
    p = Pool(processes=n)  # 设置进程池大小, 从无到有, 并之后只有这四个进程执行任务
    li = []
    start_time = time.time()
    for i in range(10):
        res = p.apply_async(test,args=(2,))  # 开启十个任务, 使用异步调用的方式
        li.append(res)
    p.close()  # 关闭进程池, 不会再有新的进程加入到pool中, 防止进一步的操作
    p.join()   # join必须在close函数之后进行, 否则报错, 执行后等待所有子进程结束
    print(li)  # 返回的是AsyncResul的对象[<multiprocessing.pool.ApplyResult object at 0x000002318511B408>,....]
    print([i.get() for i in li])  # 使用get方法来获取异步调用的值(同步调用没有该方法),并放入列表中打印
    print(f"使用时间:{time.time()-start_time}")

'''输出
子进程:8636
子进程:10828
子进程:7432
子进程:13976
子进程:8636
子进程:10828
子进程:7432
子进程:13976
子进程:8636
子进程:10828
[<multiprocessing.pool.ApplyResult object at 0x000001623059B308>,...省略]
[16, 24, 24, 24, 16, 28, 36, 28, 8, 32]
使用时间:6.301024436950684
'''

从上面结果也能看出自始至终都只有四个进程在工作 : 8636、10828、7432、13976,异步调用方式如果任务进行时遇到阻塞操作将立马接收其它异步操作中的结果, 如果进程池满了, 则只能等待任务进行完毕拿到结果, 拿到的结果是 AsyncResul 的对象, 需要使用 get 方法取值, 用时 6 秒多一点

6.服务端使用进程池来控制接入客户端进程的个数示例

  • 服务端
from socket import *
from multiprocessing import Pool
import os

s = socket(AF_INET,SOCK_STREAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)  # 重用IP和端口
s.bind(("127.0.0.1",8055))
s.listen(5)

def connection(conn):
    print(f"当前进程:{os.getpid()}")
    while 1:
        try:
            date = conn.recv(1024)
            if len(date) == 0:break
            conn.send("阿巴阿巴".encode("utf-8"))
        except Exception:
            break

if __name__ == '__main__':
    p = Pool(2)  # 不指定,默认本机CPU核数
    print("connection....")
    while 1:
        conn,addr = s.accept()
        print(f"已连上{addr}")
        p.apply_async(connection,args=(conn,))
  • 客户端(我们开启四个客户端来做实验)
from socket import *

c = socket(AF_INET,SOCK_STREAM)
c.connect(("127.0.0.1",8055))

while 1:
    msg = input("内容>>").strip()
    if len(msg) == 0:continue
    c.send(msg.encode("utf-8"))
    date = c.recv(1024)
    print(f"服务端的回复:{date.decode('utf-8')}")
  • 测试效果

四个客户端一个服务端 :

image-20210123173810653

启动五台机器, 让四台客户端发送信息

前两台能发收消息, 后两台阻塞原地


image-20210123174103928

image-20210123174114486

image-20210123174127446

image-20210123174135593

服务端显示两个进程启动成功 : 8928、17584, 剩余两个阻塞


image-20210123174240246

我们将前面两个客户端进程关闭, 看看进程号是否变化

关闭前两个客户端进程之后, 后两个客户端进程立马启动起来了, 并且发现PID还是原来的两个

三.回调函数 (callback)

1.什么是回调函数

将第一个函数的指针(也就是内存地址,Python中淡化了指针的概念)作为参数传给另一个函数处理, 这第一个函数就称为回调函数

2.简单示例

def foo(n):
    print(f"foo输出{n}")

def Bar(i,func):
    func(i)

for i in range(3):
    Bar(i,foo)
    
'''输出
foo输出0
foo输出1
foo输出2
'''

3.回调函数应用场景

当进程池中一个任务处理完之后, 它去通知主进程自己结束了, 让主进程处理自己的结果, 于是主进程去调用另一个函数去处理该结果, 我们可以将耗时间或者阻塞的任务放入进程池, 在主进程中指定回调函数, 并由主进程负责执行, 这样主进程在执行回调函数的时候就省去了I/O的过程, 直接拿到的就是任务的结果

  • 举一个简单易于理解的示例
from multiprocessing import Pool
import os

def get(n):
    print(f"get--->{os.getpid()}")
    return n   # 返回任务执行的结果

def set(num):  # 拿到回调函数的处理结果--->num
    print(f"set--->{os.getpid()} : {num**2}")

if __name__ == '__main__':
    p = Pool(3)
    nums = [2,3,4,1]
    li = []
    for i in nums:
        # 异步调用,并使用callback设置回调
        res = p.apply_async(get,args=(i,),callback=set)  
        li.append(res)

    p.close()  # 关闭进程池
    p.join()   # 等待子进程结束
    print([ii.get() for ii in li])  # 使用get方法拿到结果
    
'''输出
get--->8388
get--->8388
set--->8768 : 4
get--->8388
set--->8768 : 9
get--->8388
set--->8768 : 16
set--->8768 : 1
[2, 3, 4, 1]
'''
  • 获取网页源码大小示例
from multiprocessing import Pool
import requests,os

def get_htm(url):
    print(f"进程:{os.getpid()}开始获取:{url}网页")
    response = requests.get(url)
    if response.status_code == 200:   # 如果是200,则获取成功
        return {'url':url,'text':response.text}
    else:
        return {'url':url,'text':''}  # 有些网页获取不到,设置空

def parse_htm(htm_dic):
    print(f'进程:{os.getpid()}正在处理:{htm_dic["url"]}的text')
    parse_data = f"url:{htm_dic['url']} size:{len(htm_dic['text'])}"
    with open("./db.txt","a")as f:    # 将URL和对应网页源码大小保存到文件
        f.write(f"{parse_data}\n")

if __name__ == '__main__':
    urls=[
        'https://zhuanlan.zhihu.com',
        'https://www.cnblogs.com',
        'https://www.python.org',
        'https://blog.csdn.net',
        'http://www.china.com.cn',
    ]
    p = Pool(3)  # 设置进程池最大进程数为3
    li = []
    for url in urls:
        # 异步调用并设置回调
        res = p.apply_async(get_htm,args=(url,),callback=parse_htm)  
        li.append(res)

    p.close()  # 关闭进程池
    p.join()   # 等待子进程结束
    print([i.get() for i in li])  # 使用get方法获取结果
    
'''输出
进程:11484开始获取:https://zhuanlan.zhihu.com网页
进程:17344开始获取:https://www.cnblogs.com网页
进程:2688开始获取:https://www.python.org网页
进程:11484开始获取:https://blog.csdn.net网页
进程:3928正在处理:https://zhuanlan.zhihu.com的text
进程:17344开始获取:http://www.china.com.cn网页
进程:3928正在处理:https://www.cnblogs.com的text
进程:3928正在处理:https://blog.csdn.net的text
进程:3928正在处理:http://www.china.com.cn的text
进程:3928正在处理:https://www.python.org的text
[{'url': 'https://zhuanlan.zhihu.com', 'text': ''},...一堆网页源码的bytes(省略)]
'''
  • 查看一下保存的 “db.txt” 文件


image-20210123220247697

4.爬取福布斯全球排行榜


image-20210123233054258

from multiprocessing import Pool
import re
import requests

def get_htm(url,format1):
    response = requests.get(url)
    if response.status_code == 200:
        return (response.text,format1)
    else:
        return ('',format1)

def parse_htm(res):
    text,format1 = res
    data_list = re.findall(format1,text)
    for data in data_list:
        with open("福布斯排行.txt","a",encoding="utf-8")as f:
            f.write(f"排名:{data[0]},名字:{data[1]},身价:{data[2]},公司:{data[3]},国家:{data[4]}\n")

if __name__ == '__main__':
    url1 = "https://www.phb123.com/renwu/fuhao/shishi.html"
    # 使用正则匹配关键字
    format1 = re.compile(r'<td.*?"xh".*?>(\d+)<.*?title="(.*?)".*?alt.*?<td>(.*?)</td>.*?<td>(.*?)<.*?title="(.*?)"', re.S)
    url_list = [url1]
    for i in range(2, 16):  # 总共15页排行,将链接都加进列表里
        url_list.append(f"https://www.phb123.com/renwu/fuhao/shishi_{i}.html")
    p = Pool()
    li = []
    for url in url_list:
        res = p.apply_async(get_htm,args=(url,format1),callback=parse_htm)
        li.append(res)

    p.close()
    p.join()
    print("保存完成")
  • 查看一下文件, 看看自己有没有上榜

image-20210123232324652

image-20210123232352767

ps : 如果你就是想在主进程中等待进程池中所有任务都执行完毕后,再统一处理结果,则无需回调函数

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

进程池(multiprocess.Pool) 的相关文章

  • 什么是MariaDB中的thread pool,连接池简介

    Thread pool是什么 MySQL是每个连接上来都要创建一个线程来执行语句 这样每一个新的连接进来即会创建一个新的线程 xff0c 这种动作对MySQL本身压力比较大 Threadpool是提供一种线程代理的模型执行每个连接的语句 而
  • node-red mysql节点报错“Pool is Closed”

    进入nodejs安装目录 执行以下命令 npm install mysql 重启node red pm2 restart all 问题解决
  • Python的多进程实现

    原文链接 https www liaoxuefeng com wiki 1016959663602400 1017628290184064 要让Python程序实现多进程 multiprocessing 我们先了解操作系统的相关知识 Uni
  • ThreadPoolExecutor是如何处理任务的异常情况

    本文因生产环境线程池某些场景下的任务异常后 日志文件中没有被记录进来产生的困惑引发的思考 当然如果所有异步的业务方法run里面都加上一层try catch 就可以主动捕获所有的异常 也能够记录到日志文件中 然而总有一些人总有一些时候不小心漏
  • Python,使用多处理比不使用慢

    在花了很多时间尝试了解多处理之后 我想出了这段代码 这是一个基准测试 示例1 from multiprocessing import Process class Alter Process def init self word Proces
  • 什么是沙发底池

    In 沙发底座网址 例如服务器 端口 池 默认 沙发底座池到底是什么 它总是默认的还是我们可以更改它 那里写着一些文字 http www couchbase com docs couchbase manual 1 8 couchbase a
  • Python,多线程太慢,多进程

    我是多处理新手 我了解一些有关线程的知识 但我需要提高计算速度 希望通过多重处理 示例说明 将字符串发送到线程 更改字符串 基准测试 将结果发回打印 from threading import Thread class Alter Thre
  • java中的字符串池

    Java有字符串池 因此字符串类的对象是不可变的 但我的问题是 创建 String POOL 的必要性是什么 为什么字符串类不像其他类那样保留它自己的值 JVM 内部是否需要一些字符串 或者这是性能优势 如果是的话怎么办 池是可能的 因为字
  • 如何在类中并行化 python 中的 for ?

    我有一个 python 函数funz每次都会返回长度为 p 的不同数组 我需要多次运行该函数 然后计算每个值的平均值 我可以使用 for 循环来完成此操作 但需要很多次 我正在尝试使用库多处理 但遇到错误 import sklearn as
  • 如何防止在 boost::fast_pool_allocator 管理的对象上调用析构函数?

    我想利用以下广告功能boost fast pool allocator see Boost Pool 的 Boost 文档 例如 您可能会遇到这样的情况 您想要分配一个 一堆小物体在一个点上 然后到达你的一个点 不再需要它们的程序 使用池接
  • Python 多处理池 OSError:打开的文件太多

    我得检查一下需要多少时间do something 总共需要一对包含 30k 元素的列表 下面是我的代码 def run a b data p datetime datetime now val do something a b data 0
  • 如何在 IIS 中监视 .NET MySQL 数据连接器的连接池

    我已经在谷歌上搜索了相当多的信息 但无法找到确切的答案 我们在日志中看到以下错误 超时已过 获取之前已过了超时时间 来自池的连接 发生这种情况的原因可能是所有 连接正在使用中并且已达到最大池大小 堆栈跟踪 位于 MySql Data MyS
  • “托管共享内存”应该分配多少内存? (促进)

    我正在寻找一个明确的答案 如果确实存在 关于通过创建静态共享内存块时应该分配多少内存boost interprocess s managed shared memory Even 官方例子 http www systomath com in
  • 修复配置错误的镜像 zfs 池

    我的机器从两个 USB 设备的镜像 zfs 池启动 以前的泳池是这样的 sudo zpool status pool freenas boot state ONLINE scan resilvered 891M in 15h19m with
  • 字符串池:“Te”+“st”比“Test”快?

    我正在尝试一些有关字符串池的性能基准 然而 结果并不令人期待 我做了3个静态方法 Perform0 方法 每次都会创建一个新对象 Perform1 方法 字符串文字 Test Perform2 方法 字符串常量表达式 Te st 我的期望是
  • 多处理池内进程超时

    当我使用以下代码时 池结果总是返回超时 我在做的事情在逻辑上是否不正确 from multiprocessing import Pool Process cpu count def add num return num 1 def add
  • 合并从 python 多进程调用函数返回的数据帧

    from multiprocessing import Pool with Pool processes 6 as p p starmap update tabl zip r 我正在使用此处概述的方法 https web archive o
  • 如何限制 Glassfish v3 上 MDB 池的大小

    我的消息驱动 Bean 执行高度密集的操作 因此我想限制它的池大小 否则我的服务器会过载 我已经尝试过这个 代码 但它不起作用 它的池仍然是32 根据经验测试 我不时重新启动服务器 因此没有池实例 MessageDriven mappedN
  • 在 Perl 中,如何从父进程向子进程发送消息(或信号),反之亦然?

    我正在编写一个管理多进程的程序 这就是我所做的 而且效果很好 但现在 我想将消息从子进程发送到父进程 反之亦然 从父进程到子进程 你知道最好的方法吗 你知道我所做的是否是我想要的正确方法 从子进程到父进程发送消息 信号或共享内存 反之亦然
  • boost::pool<>::malloc 和 boost::pool<>::ordered_malloc 之间有什么区别,什么时候应该使用 boost::pool<>::ordered_malloc?

    我正在使用 boost pool 但我不知道什么时候使用boost pool lt gt malloc and boost pool lt gt ordered malloc so 有什么区别boost pool lt gt malloc

随机推荐

  • Python爬虫基础之三

    Python爬虫基础包括HTTP协议 HTML CSS和JavaScript语言基础 requests库的使用 Beautiful Soup库的使用 xpath和正则表达式的使用等 此外 xff0c 还应该了解反爬虫机制和爬虫的一些常见问题
  • 最容易上手的爬虫项目

    今天和大家分享一个爬取项目 xff0c 那就是爬取自己博客的项目 1 确定爬取的目标 开始之前我们需要确定一个爬取的目标 xff0c 从我自己博客的首页进入 在这个例子里面我们要写一个爬虫将我的的文章列表拉出来 xff0c 保存在一个JSO
  • OpenCV中的相机标定

    之前在https blog csdn net fengbingchun article details 130039337 中介绍了相机的内参和外参 xff0c 这里通过OpenCV中的接口实现对内参和外参的求解 估计相机参数的过程称为相机
  • 应用scrapy爬虫框架

    Scrapy是一个基于Python的开源网络爬虫框架 xff0c 它可以帮助我们快速 高效地抓取网页数据 xff0c 并支持数据的自动化处理 存储和导出 Scrapy提供了丰富的扩展机制 xff0c 可以轻松地实现各种自定义需求 Scrap
  • 爬虫为什么需要ip

    爬虫需要使用爬虫ip主要是为了解决以下问题 xff1a 1 反爬虫机制 xff1a 许多网站会设置反爬虫机制来防止爬虫程序的访问 xff0c 例如限制IP地址的访问频率 检测访问来源等 使用爬虫ip可以绕过这些限制 xff0c 使得爬虫程序
  • scrapy 爬虫中间件的学习

    Scrapy中间件是一个处理Scrapy请求和响应的机制 中间件可以在请求或响应被Scrapy引擎处理之前或之后对其进行修改或操作 xff0c 用于实现诸如缓存 代理 用户代理等功能 Scrapy中间件的作用主要有以下几个方面 xff1a
  • Python爬虫需要哪些基础

    Python爬虫是指使用Python语言编写程序 xff0c 自动化地访问Web页面并抓取其中的信息 以下是Python爬虫的基础知识 xff1a 爬虫的工作原理 xff1a 爬虫程序通过网络请求获取Web页面的HTML源码 xff0c 然
  • 极简爬虫通用模板

    网络爬虫的一般步骤如下 xff1a 1 确定爬取目标 xff1a 确定需要爬取的数据类型和来源网站 2 制定爬取策略 xff1a 确定爬取哪些网页 如何爬取和频率等 3 构建爬虫程序 xff1a 使用编程语言 xff08 如Python x
  • Python爬虫常用框架

    大家都知道python是一门多岗位编程语言 xff0c 学习python之后可以从事的岗位有很多 xff0c python爬虫便在其中 xff0c 不过很多人对python不是很了解 xff0c 所以也不知道python爬虫是什么 xff0
  • Python多线程爬虫简单模板

    多线程爬虫的流程可以大致分为 xff1a xff08 1 xff09 获取种子URL xff1a 从初始URL中抓取起始页面 xff0c 解析其中的URL xff0c 并将这些URL添加到未访问的URL队列中 xff1b xff08 2 x
  • scrapy爬虫标准流程

    Scrapy爬虫的标准流程一般包括以下几个步骤 xff1a 1 明确需求和目标网站的结构 xff0c 确定需要爬取的数据以及爬取规则 2 创建一个Scrapy项目 xff0c 使用命令行工具创建一个新的Scrapy项目 3 定义数据模型和i
  • Python爬虫设置代理

    在Python中使用代理进行爬虫操作可以有效地隐藏用户的真实IP地址 xff0c 防止被封禁或者限制访问 下面是设置代理的示例代码 xff1a span class token keyword import span requests pr
  • Golang 网络爬虫框架gocolly

    Golang 是一门非常适合编写网络爬虫的语言 xff0c 它有着高效的并发处理能力和丰富的网络编程库 下面是一个简单的 Golang 网络爬虫示例 xff1a package main span class token keyword i
  • Python中txt中内容解析到json文件

    在instant ngp中通过调用scripts colmap2nerf py可以自动生成transforms json文件 xff0c 即相机参数 xff0c 但有时会从相机本身获取到这些参数 xff0c 为了将每个相机参数信息即txt内
  • 代理ip在爬虫中的应用

    代理IP在爬虫中的应用主要是为了解决以下两个问题 xff1a IP封禁问题 很多网站为了防止爬虫 xff0c 会对频繁访问的IP进行封禁 xff0c 这样就会导致爬虫无法继续访问 此时 xff0c 使用代理IP可以隐藏真实IP xff0c
  • 使用VNC远程服务器

    通常我们控制服务器都是通过ssh远程命令行 但是这次由于特殊需求需要进入服务器的图形界面进行操作 xff08 这台服务器安装的时候就是安装的gnome图形界面 xff0c 但是由于没有事先在服务器上安装向日葵等远程软件 xff0c 所以无法
  • 安卓adb命令大全

    安卓官方文档 xff1a https developer android google cn studio command line adb hl 61 zh cn ADB xff0c 即 Android Debug Bridge xff0
  • Python运维自动化psutil 模块详解(超级详细)

    psutil 模块 参考官方文档 xff1a https pypi org project psutil 一 psutil简介 psutil是一个开源且跨平台 xff08 http code google com p psutil xff0
  • 2021最强Python学习教程,从零基础入门到精通

    关于本套Python自学视频教程 xff1a B站链接 xff1a 戳我直达 千锤百炼 xff0c 只为大作 xff1b 精益求精 xff0c 处处斟酌 xff1b 这种教程 xff0c 看一眼就倾心 你准备好了吗 文章目录 你准备好了吗
  • 进程池(multiprocess.Pool)

    进程池 multiprocess Pool 一 进程池概念 1 什么是进程池 x1f449 进程池是资源进程 管理进程组成的技术的应用 2 为什么要有进程池 x1f62e 忙时会有成千上万的任务需要被执行 xff0c 闲时可能只有零星任务