Python3多进程(mutiprocessing)

2023-11-19

和Threading的比较

多进程 Multiprocessing 和多线程 threading 类似, 他们都是在 python 中用来并行运算的. 不过既然有了 threading, 为什么 Python 还要出一个 multiprocessing 呢? 原因很简单, 就是用来弥补 threading 的一些劣势, 比如在 threading 教程中提到的GIL.

使用 multiprocessing 也非常简单, 如果对 threading 有一定了解的朋友, 你们的享受时间就到了. 因为 python 把 multiprocessing 和 threading 的使用方法做的几乎差不多. 这样我们就更容易上手. 也更容易发挥你电脑多核系统的威力了!

添加进程process

导入进程标准模块

import multiprocessing as mp
import threading as td

定义一个被线程和进程调用的函数

def job(a,d):
    print('aaaaa')

创建线程和进程

t1 = td.Thread(target=job,args=(1,2))
p1 = mp.Process(target=job,args=(1,2))

注意:Thread和Process的首字母都要大写,被调用的函数没有括号,被调用的函数的参数放在args(…)中

分别启动线程和进程

t1.start()
p1.start()

分别连接线程和进程

t1.join()
p1.join()

完整的线程和进程创建对比代码

import multiprocessing as mp
import threading as td

def job(a,d):
    print('aaaaa')

t1 = td.Thread(target=job,args=(1,2))
p1 = mp.Process(target=job,args=(1,2))
t1.start()
p1.start()
t1.join()
p1.join()

从上面的使用对比代码可以看出,线程和进程的使用方法相似

运用

在运用时需要添加上一个定义main函数的语句

if __name__=='__main__':

完整的应用代码:

import multiprocessing as mp

def job(a,d):
    print('aaaaa')

if __name__=='__main__':
    p1 = mp.Process(target=job,args=(1,2))
    p1.start()
    p1.join()

运行环境要在terminal环境下,可能其他的编辑工具会出现运行结束后没有打印结果,在terminal中的运行后打印的结果为:

aaaaa

存储进程输出Queue

Queue的功能是将每个核或线程的运算结果放在队里中, 等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。原因很简单, 多线程调用的函数不能有返回值, 所以使用Queue存储多个线程运算的结果

把结果放在Queue里

定义一个被多线程调用的函数,q 就像一个队列,用来保存每次函数运行的结果

#该函数没有返回值!!!
def job(q):
    res=0
    for i in range(1000):
        res+=i+i**2+i**3
    q.put(res)    #queue

主函数

定义一个多线程队列,用来存储结果

if __name__=='__main__':
    q = mp.Queue()

定义两个线程函数,用来处理同一个任务, args 的参数只要一个值的时候,参数后面需要加一个逗号,表示args是可迭代的,后面可能还有别的参数,不加逗号会出错

p1 = mp.Process(target=job,args=(q,))
p2 = mp.Process(target=job,args=(q,))

分别启动、连接两个线程

p1.start()
p2.start()
p1.join()
p2.join()

上面是分两批处理的,所以这里分两批输出,将结果分别保存
join 是为了让分线程还没结束时, 主线程也不结束

res1 = q.get()
res2 = q.get()

打印最后的运算结果

print(res1+res2)

完整代码

import multiprocessing as mp

def job(q):
    res=0
    for i in range(1000):
        res+=i+i**2+i**3
    q.put(res)    #queue

if __name__=='__main__':
    q = mp.Queue()
    p1 = mp.Process(target=job,args=(q,))
    p2 = mp.Process(target=job,args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print(res1+res2)

运行的时候还是要在terminal中,最后运行结果为

499667166000

效率对比 threading&multiprocessing

创建多进程mutiprocessing

和上节一样,首先import multiprocessing并定义要实现的job(),同时为了容易比较,我们将计算的次数增加到1000000

import multiprocessing as mp

def job(q):
    res = 0
    for i in range(1000000):
        res += i + i**2 + i**3
    q.put(res) # queue

因为多进程是多核运算,所以我们将上节的多进程代码命名为multicore()

def multicore():
    q = mp.Queue()
    p1 = mp.Process(target=job, args=(q,))
    p2 = mp.Process(target=job, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print('multicore:',res1 + res2)

创建多线程mutithread

接下来创建多线程程序,创建多线程和多进程有很多相似的地方。首先import threading然后定义multithread()完成同样的任务

import threading as td

def multithread():
    q = mp.Queue() # thread可放入process同样的queue中
    t1 = td.Thread(target=job, args=(q,))
    t2 = td.Thread(target=job, args=(q,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    res1 = q.get()
    res2 = q.get()
    print('multithread:', res1 + res2)

创建普通函数

最后我们定义最普通的函数。注意,在上面例子中我们建立了两个进程或线程,均对job()进行了两次运算,所以在normal()中我们也让它循环两次

def normal():
    res = 0
    for _ in range(2):
        for i in range(1000000):
            res += i + i**2 + i**3
    print('normal:', res)

运行时间

最后,为了对比各函数运行时间,我们需要import time, 然后依次运行定义好函数:

import time

if __name__ == '__main__':
    st = time.time()
    normal()
    st1 = time.time()
    print('normal time:', st1 - st)
    multithread()
    st2 = time.time()
    print('multithread time:', st2 - st1)
    multicore()
    print('multicore time:', time.time() - st2)

大功告成,下面我们来看下实际运行对比。

结果对比

"""
# range(1000000)
('normal:', 499999666667166666000000L)
('normal time:', 1.1306169033050537)
('thread:', 499999666667166666000000L)
('multithread time:', 1.3054230213165283)
('multicore:', 499999666667166666000000L)
('multicore time:', 0.646507978439331)
"""

普通/多线程/多进程的运行时间分别是1.13,1.3和0.64秒。 我们发现多核/多进程最快,说明在同时间运行了多个任务。 而多线程的运行时间居然比什么都不做的程序还要慢一点,说明多线程还是有一定的短板的(GIL)。

我们将运算次数加十倍,再来看看三种方法的运行时间:

"""
# range(10000000)
('normal:', 4999999666666716666660000000L)
('normal time:', 40.041773080825806)
('thread:', 4999999666666716666660000000L)
('multithread time:', 41.777158975601196)
('multicore:', 4999999666666716666660000000L)
('multicore time:', 22.4337899684906)
"""

这次运行时间依然是 多进程 < 普通 < 多线程,由此我们可以清晰地看出哪种方法更有效率。

进程池Pool

这次我们讲进程池Pool。 进程池就是我们将所要运行的东西,放到池子里,Python会自行解决多进程的问题

首先import multiprocessing和定义job()

import multiprocessing as mp

def job(x):
    return x*x

进程池Pool()和map()

然后我们定义一个Pool

pool = mp.Pool()

有了池子之后,就可以让池子对应某一个函数,我们向池子里丢数据,池子就会返回函数返回的值。 Pool和之前的Process的不同点是丢向Pool的函数有返回值,而Process的没有返回值。

接下来用map()获取结果,在map()中需要放入函数和需要迭代运算的值,然后它会自动分配给CPU核,返回结果

res = pool.map(job, range(10))

让我们来运行一下

def multicore():
    pool = mp.Pool()
    res = pool.map(job, range(10))
    print(res)

if __name__ == '__main__':
    multicore()

运行结果:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

自定义核数量

我们怎么知道Pool是否真的调用了多个核呢?我们可以把迭代次数增大些,然后打开CPU负载看下CPU运行情况

打开CPU负载(Mac):活动监视器 > CPU > CPU负载(单击一下即可)

Pool默认大小是CPU的核数,我们也可以通过在Pool中传入processes参数即可自定义需要的核数量,

def multicore():
    pool = mp.Pool(processes=3) # 定义CPU核数量为3
    res = pool.map(job, range(10))
    print(res)

apply_async()

Pool除了map()外,还有可以返回结果的方式,那就是apply_async().

apply_async()中只能传递一个值,它只会放入一个核进行运算,但是传入值时要注意是可迭代的,所以在传入值后需要加逗号, 同时需要用get()方法获取返回值

def multicore():
    pool = mp.Pool() 
    res = pool.map(job, range(10))
    print(res)
    res = pool.apply_async(job, (2,))
    # 用get获得结果
    print(res.get())

运行结果;

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]  # map()
4 # apply_async()

用apply_async()输出多个结果

那么如何用apply_async()输出多个迭代呢?

我们在apply_async()中多传入几个值试试

res = pool.apply_async(job, (2,3,4,))

结果会报错:

TypeError: job() takes exactly 1 argument (3 given)

即apply_async()只能输入一组参数。

在此我们将apply_async() 放入迭代器中,定义一个新的multi_res

multi_res = [pool.apply_async(job, (i,)) for i in range(10)]

同样在取出值时需要一个一个取出来

print([res.get() for res in multi_res])

合并代码

def multicore():
    pool = mp.Pool() 
    res = pool.map(job, range(10))
    print(res)
    res = pool.apply_async(job, (2,))
    # 用get获得结果
    print(res.get())
    # 迭代器,i=0时apply一次,i=1时apply一次等等
    multi_res = [pool.apply_async(job, (i,)) for i in range(10)]
    # 从迭代器中取出
    print([res.get() for res in multi_res])

运行结果

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # map()
4 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # multi_res

可以看出在apply用迭代器的得到的结果和用map得到的结果是一样的

总结

Pool默认调用是CPU的核数,传入processes参数可自定义CPU核数
map() 放入迭代参数,返回多个结果
apply_async()只能放入一组参数,并返回一个结果,如果想得到map()的效果需要通过迭代

共享内存shared memory

这节我们学习如何定义共享内存。只有用共享内存才能让CPU之间有交流。

Shared Value

我们可以通过使用Value数据存储在一个共享的内存表中。

import multiprocessing as mp

value1 = mp.Value('i', 0) 
value2 = mp.Value('d', 3.14)

其中d和i参数用来设置数据类型的,d表示一个双精浮点类型,i表示一个带符号的整型。更多的形式请查看本页最后的表.

Shared Array

在Python的mutiprocessing中,有还有一个Array类,可以和共享内存交互,来实现在进程之间共享数据。

array = mp.Array('i', [1, 2, 3, 4])

这里的Array和numpy中的不同,它只能是一维的,不能是多维的。同样和Value 一样,需要定义数据形式,否则会报错。 我们会在后一节举例说明这两种的使用方法.

错误形式

array = mp.Array('i', [[1, 2], [3, 4]]) # 2维list

"""
TypeError: an integer is required
"""

参考数据形式

各参数代表的数据类型

| Type code | C Type             | Python Type       | Minimum size in bytes |
| --------- | ------------------ | ----------------- | --------------------- |
| `'b'`     | signed char        | int               | 1                     |
| `'B'`     | unsigned char      | int               | 1                     |
| `'u'`     | Py_UNICODE         | Unicode character | 2                     |
| `'h'`     | signed short       | int               | 2                     |
| `'H'`     | unsigned short     | int               | 2                     |
| `'i'`     | signed int         | int               | 2                     |
| `'I'`     | unsigned int       | int               | 2                     |
| `'l'`     | signed long        | int               | 4                     |
| `'L'`     | unsigned long      | int               | 4                     |
| `'q'`     | signed long long   | int               | 8                     |
| `'Q'`     | unsigned long long | int               | 8                     |
| `'f'`     | float              | float             | 4                     |
| `'d'`     | double             | float             | 8                     |

进程锁Lock

不加进程锁

让我们看看没有加进程锁时会产生什么样的结果。

import multiprocessing as mp
import time

def job(v, num):
    for _ in range(5):
        time.sleep(0.1) # 暂停0.1秒,让输出效果更明显
        v.value += num # v.value获取共享变量值
        print(v.value, end="")

def multicore():
    v = mp.Value('i', 0) # 定义共享变量
    p1 = mp.Process(target=job, args=(v,1))
    p2 = mp.Process(target=job, args=(v,3)) # 设定不同的number看如何抢夺内存
    p1.start()
    p2.start()
    p1.join()
    p2.join()

if __name__ == '__main__':
    multicore()

在上面的代码中,我们定义了一个共享变量v,两个进程都可以对它进行操作。 在job()中我们想让v每隔0.1秒输出一次累加num的结果,但是在两个进程p1和p2 中设定了不同的累加值。所以接下来让我们来看下这两个进程是否会出现冲突。

运行一下:

1
4
5
8
9
12
13
16
17
20

我们可以看到,进程1和进程2在相互抢着使用共享内存v。

加进程锁

为了解决上述不同进程抢共享资源的问题,我们可以用加进程锁来解决。

首先需要定义一个进程锁

 l = mp.Lock() # 定义一个进程锁

然后将进程锁的信息传入各个进程中

p1 = mp.Process(target=job, args=(v,1,l)) # 需要将Lock传入
    p2 = mp.Process(target=job, args=(v,3,l)) 

在job()中设置进程锁的使用,保证运行时一个进程的对锁内内容的独占

def job(v, num, l):
    l.acquire() # 锁住
    for _ in range(5):
        time.sleep(0.1) 
        v.value += num # v.value获取共享内存
        print(v.value)
    l.release() # 释放

完整代码:

def job(v, num, l):
    l.acquire() # 锁住
    for _ in range(5):
        time.sleep(0.1) 
        v.value += num # 获取共享内存
        print(v.value)
    l.release() # 释放

def multicore():
    l = mp.Lock() # 定义一个进程锁
    v = mp.Value('i', 0) # 定义共享内存
    p1 = mp.Process(target=job, args=(v,1,l)) # 需要将lock传入
    p2 = mp.Process(target=job, args=(v,3,l)) 
    p1.start()
    p2.start()
    p1.join()
    p2.join()

if __name__ == '__main__':
    multicore()

运行一下,让我们看看是否还会出现抢占资源的情况:

1
2
3
4
5
8
11
14
17
20

显然,进程锁保证了进程p1的完整运行,然后才进行了进程p2的运行

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

Python3多进程(mutiprocessing) 的相关文章

  • Python3+Kivy+Plyer 推送通知图标问题

    我在使用 Android 的简单通知测试应用程序时遇到了一个奇怪的错误 错误 python AttributeError type object notification org notificator R drawable has no
  • 在 python 2 和 3 的spyder之间切换

    根据我在文档中了解到的内容 它指出您只需使用命令提示符创建一个新变量即可轻松在 2 个 python 环境之间切换 如果我已经安装了 python 2 7 则 conda create n python34 python 3 4 anaco
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 无法将 datetime.datetime 与 datetime.date 进行比较

    我有以下代码并收到上述错误 由于我是 python 新手 我无法理解这里的语法以及如何修复错误 if not start or date lt start start date 有一个datetime date 从日期时间转换为日期的方法
  • 如何在“python setup.py test”中运行 py.test 和 linter

    我有一个项目setup py文件 我用pytest作为测试框架 我还在我的代码上运行各种 linter pep8 pylint pydocstyle pyflakes ETC 我用tox在多个 Python 版本中运行它们 并使用以下命令构
  • 如何在 openpyxl 中设置或更改表格的默认高度

    我想通过openpyxl更改表格高度 并且我希望首先默认一个更大的高度值 然后我可以设置自动换行以使我的表格更漂亮 但我不知道如何更改默认高度 唯一的到目前为止 我知道更改表格高度的方法是设置 row dimension idx heigh
  • 在python中调用subprocess.Popen时“系统找不到指定的文件”

    我正在尝试使用svnmerge py合并一些文件 它在底层使用 python 当我使用它时 我收到一个错误 系统找不到指定的文件 工作中的同事正在运行相同版本的svnmerge py 以及 python 2 5 2 特别是 r252 609
  • 使用 Python 解析 XML,解析外部 ENTITY 引用

    在我的 S1000D xml 中 它指定了一个带有对公共 URL 的引用的 DOCTYPE 该 URL 包含对包含所有有效字符实体的许多其他文件的引用 我使用 xml etree ElementTree 和 lxml 尝试解析它并得到解析错
  • 以编程方式将列名称添加到 numpy ndarray

    我正在尝试将列名称添加到 numpy ndarray 然后按名称选择列 但这不起作用 我无法判断问题是在添加名称时出现 还是在稍后尝试调用它们时出现 这是我的代码 data np genfromtxt csv file delimiter
  • Python 相当于 Bit Twiddling Hacks 中的 C 代码?

    我有一个位计数方法 我正在尝试尽可能快地实现 我想尝试下面的算法位摆弄黑客 http graphics stanford edu seander bithacks html CountBitsSetParallel 但我不知道 C 什么是
  • 如何检查包含 NaN 的列表 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 在我的 for 循环中 我的代码生成一个如下所示的列表 list 0 0 0 0 sum 0 0 0 0 该循环生成所有其他数字向量 但它也
  • 如何像在浏览器中一样检索准确的 HTML

    我正在使用 Python 脚本来呈现网页并检索其 HTML 它适用于大多数页面 但对于其中一些页面 检索到的 HTML 不完整 我不太明白为什么 这是我用来废弃此页面的脚本 由于某种原因 每个产品的链接不在 HTML 中 Link http
  • 从 python 中的缩进文本文件创建树/深度嵌套字典

    基本上 我想迭代一个文件并将每行的内容放入一个深层嵌套的字典中 其结构由每行开头的空格数量定义 本质上 目标是采取这样的事情 a b c d e 并将其变成这样的东西 a b c d e Or this apple colours red
  • Docker 日志中的 Python 异常标记为流:stdout

    我想解析和处理来自 docker 容器的所有错误 但当我期望 stderr 时 Python 异常标记为 stdout 举个简单的例子app py raise Exception 然后我在 docker 容器中运行这个文件 但在 var l
  • PermanentTaskFailure:“模块”对象没有属性“迁移”

    我在 google appengine 上使用 Nick Johnson 的批量更新库 http blog notdot net 2010 03 Announcing a robust datastore bulk update utili
  • python 中的基本矩阵转置

    我尝试了 python 中矩阵转置的最基本方法 但是 我没有得到所需的结果 接下来是代码 A 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 print A def TS A B A for i in range len A
  • python csv按列转换为字典

    是否可以将 csv 文件中的数据读取到字典中 使得列的第一行是键 同一列的其余行构成列表的值 例如 我有一个 csv 文件 strings numbers colors string1 1 blue string2 2 red string
  • Python列表对象属性“append”是只读的

    正如标题所说 在Python中 我试图做到这一点 以便当有人输入一个选择 在本例中为Choice13 时 它会从密码列表中删除旧密码并添加新密码 passwords mrjoebblock mrjoefblock mrjoegblock m
  • bool() 和operator.truth() 有什么区别?

    bool https docs python org 3 library functions html bool and operator truth https docs python org 3 library operator htm
  • 将数组从 .npy 文件读入 Fortran 90

    我使用 Python 以二维数组 例如 X 的形式生成一些初始数据 然后使用 Fortran 对它们进行一些计算 最初 当数组大小约为 10 000 x 10 000 时 np savetxt 在速度方面表现良好 但是一旦我开始增加数组的维

随机推荐

  • vector模拟实现

    个人简介 作者简介 大家好 我是菀枯 支持我 点赞 收藏 留言 格言 不要在低谷沉沦自己 不要在高峰上放弃努力 1 前言 大家在学习C 的时候一定会学到STL 标准模板库 这是C 标准库中最重要的组成部分 它包含了常用的数据结构和算法 今天
  • API架构的选择,RESTful、GraphQL还是gRPC

    文章目录 一 RESTful 1 什么是RESTful 2 RESTful架构的原则 3 RESTful的适用场景 4 RESTful的优点 5 RESTful的缺点 二 GraphQL 1 什么是GraphQL 2 GraphQL的原则
  • 代码检视拟定方案(已完成,非代码博文,开发流程相关)

    代码检视拟定方案 为什么要进行代码检视 提前发现代码逻辑问题 优秀的代码分享 坏味道代码警示 要求别人的同时提高对自己的要求 性能初步检查 抽象组件 函数沉淀 常量抽取 设计模式引入 解决代码审查消耗大量时间精力问题 结对编程 利于双方代码
  • 【Python123】答案集合3

    目录 猴子吃桃 自定义数学函数 素数问题 素数求和 奇偶求和 华氏度转摄氏度速查表 判断字符串结尾 统计单词的数量 各位数字之和为5的数 字符串长度 字符串加密 输出单词 大小写转换 查找指定字符 模拟洗牌 随机密码生成器 模拟生成微软序列
  • 第七章InnoDB数据存储结构

    第七章InnoDB数据存储结构 1 数据的存储结构 页 索引结构为我们提供了高效的索引方式 不过索引信息和数据记录都是保存在文件上的 确切的来说是存储在页结构中 另一方面 索引是在存储引擎中实现的 Mysql服务器上的存储引擎负责对表中数据
  • PostgreSQL清空表并保留表结构、清空数据库还原数据库为新建时的状态的方法

    清空表并保留表结构 一般情况下 我们使用delete删除表中数据 但是delete是一条数据一条数据来删除表中的数据 直至表清空 保留表结构 但是当数据量很大时 它耗时较久 其实 删除表数据但保留表结构使用truncate更快速安全 使用方
  • ubuntu18.04配置cuda(RTX3080Ti)

    10系的显卡换成30系显卡后 之前配好的深度学习环境出现了兼容问题 索性重装系统 从零开始配环境 过程中也出现了各种对新显卡不兼容的情况 以下的配置是本人摸索最终成功的版本 特此记录一下 首先就是安装ubuntu18 04 这个不是本文的重
  • 常见改机软件及其原理

    1 改机原理分析 1 1 IOS设备改机原理 在iOS上目前所有流行的改机工具 本质上是利用substrate框架对某些用来获取设备和系统参数函数进行hook 从而欺骗App达到修改的目的 具体如下 用作获取设备参数的函数 无论是C函数 还
  • 蓝桥杯-2020年省赛-回文日期

    498 import datetime n input start datetime date int n 4 int n 4 6 int n 6 delta datetime timedelta days 1 flag 0 for i i
  • Ubuntu的快乐学习2——SnowBoy语音唤醒

    Ubuntu的快乐学习2 SnowBoy语音唤醒 学习前言 安装步骤 一 麦克风检测部分 1 安装pulseaudio和sox 2 安装其它软件依赖 二 获取源代码 学习前言 为了部落 安装步骤 一 麦克风检测部分 1 安装pulseaud
  • ubuntu20编译运行orb-slam3踩坑

    orb3 编译网上教程很多 写一下自己安装编译过程中踩的坑 一个半星期 终于可以跑demo了 1 出现如下问题 或者在Build target g2o时 卡住 make 2 CMakeFiles ORB SLAM3 dir build ma
  • Vue上传文件到springboot

  • Android中JNI在C/C++中的区别

    一 一个疑问 在进行JNI编程中 同样一个函数FindClass C和C 中有不同的用法 如果是C 要用 env gt FindClass str 如果是C要用 env gt FindClass env str 类似的区别几乎涉及到每一个结
  • 10 财政收入影响因素分析及预测模型

    4 10 财政收入影响因素分析及预测模型 10 1背景与挖掘目标 本案例通过研究发现影响目前以及未来地方财源建设的因素 并对其进行深入分析 提出对该市地方财源优化的具体建议 供政府决策参考 同时为其他发展较快的城市提供借鉴 本案例对1994
  • 1.Cesium介绍及环境配置

    前言 鸽了半年 flag立的太多 稿子存了100多篇 都没有开始排版整理 这些天正好学习cesium 决定每天更新一篇 提提神 一 Cesium简介 Cesium是一个用于显示三维地球的开源库 旨在释放3D数据的力量 它基于WebGL技术
  • Kmeans K均值聚类,OpenCV实现

    Clustering 聚类 kmeans k均值聚类 Finds centers of clusters and groups input samples around the clusters 寻找clusters的中心 并且将输入的样本
  • java 管程

    管程即Monitor 监视器 也叫锁 Monitor其实是一种同步机制 保证只有一个线程可以访问被保护的数据和代码 JVM中同步是基于进入和退出监视器对象 Monitor 来实现的 每个对象实例都会有一个Monitor对象 和java对象一
  • public static void main(String[] args) { //填入通过分享获取到的抖音视频地址 String videoUrl = getVid...

    这段代码的作用是从抖音 douyin 分享链接中获取视频的无水印播放地址 首先 它通过调用 HttpRequest get url 方法获取抖音视频的分享页面的 HTML 源代码 然后 通过调用 sub 方法并传入 HTML 源代码 开始字
  • 华为面试之Hr面,这个套路把我坑惨了......

    作为技术类的测试工程师面试 往往要经过多次面试才能拿到心仪的offer 这里面有技术一面 二面 甚至总监面等 还有一个必不可少的就是HR面 一般HR会出现在你面试的最前面和最后面 前面是了解你的基本情况 后面就是你已经通过了技术面试 他是来
  • Python3多进程(mutiprocessing)

    和Threading的比较 多进程 Multiprocessing 和多线程 threading 类似 他们都是在 python 中用来并行运算的 不过既然有了 threading 为什么 Python 还要出一个 multiprocess