multiprocessing--基于进程的并行教程学习(持续更新)

本文是在学习Open3D_Semantic_pointnet2_master的过程中,进而学习multiprocessing

主要流程:

  • 下载Semantic数据集,首先将txt文本转换为pts,再利用open3d的读写功能,read_point_cloud和write_point_cloud将pts文件全部转换为pcd。完成数据预处理第一步。
  • 读取写好pcd文件以及对应的label文件,将所有点非0标签去除创建索引,利用open3d,np.asarray()根据索引将点云数据都提取出来,为numpy形式,open3d.Vector3dVector()将数组形式转换为open3d形式处理。后获取min_bound,max_bound体素最大最小坐标,采用open3d.voxel_down_sample_and_trace()进行体素下的点采样,完成采样过程。
  • 再就是train()了,分配好训练数据集后,进行多进程的设置
def init_stacking():
    with tf.device("/cpu:0"):
        # Queues that contain several batches in advance
        num_train_batches = TRAIN_DATASET.get_num_batches(PARAMS["batch_size"]) #总点云/(batch_size:16 * 8192)
        """ 计算一个epoch训练需要进行多个batch,总点云数 / (batch_size * 8192 ) """
        num_validation_batches = VALIDATION_DATASET.get_num_batches(PARAMS["batch_size"])
        """ 计算验证数据集的batch"""
        stack_train = mp.Queue(num_train_batches)
        stack_validation = mp.Queue(num_validation_batches)
        stacker = mp.Process(
            target=fill_queues,
            args=(
                stack_train,
                stack_validation,
                num_train_batches,
                num_validation_batches,
            ),
        )
        stacker.start()
        return stacker, stack_validation, stack_train
def fill_queues(
    stack_train, stack_validation, num_train_batches, num_validation_batches):

    pool = mp.Pool(processes=mp.cpu_count())  #使用工作进程
    launched_train = 0
    launched_validation = 0
    results_train = []  # Temp buffer before filling the stack_train填充堆栈训练前的临时缓冲区
    results_validation = []  # Temp buffer before filling the stack_validation 填充堆栈验证之前的临时缓冲区
    # Launch as much as n
    while True:
        if stack_train.qsize() + launched_train < num_train_batches:
            results_train.append(pool.apply_async(get_batch, args=("train",)))    #返回裁剪后的盒内的点和其他信息。
            launched_train += 1
        elif stack_validation.qsize() + launched_validation < num_validation_batches:
            results_validation.append(pool.apply_async(get_batch, args=("validation",)))
            launched_validation += 1
        for p in results_train:
            if p.ready():
                stack_train.put(p.get())
                results_train.remove(p)
                launched_train -= 1
        for p in results_validation:
            if p.ready():
                stack_validation.put(p.get())
                results_validation.remove(p)
                launched_validation -= 1
        # Stability
        time.sleep(0.01)

multiprocessing学习

Pool类

引入了Pool对象,可以跨多个输入值并行化函数的执行,跨进程分配输入数据(数据并行)
以下简单例子:

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

Pool类代表进程池,Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
Pool类的几个方法:

1.apply()

函数原型:apply(func[, args=()[, kwds={}]])

该函数用于传递不定参数,同python中的apply函数一致,主进程会被阻塞直到函数执行结束(不建议使用,并且3.x以后不在出现)。

2.apply_async

函数原型:apply_async(func[, args=()[, kwds={}[, callback=None]]])

与apply用法一致,但它是非阻塞的且支持结果返回后进行回调。常用的例子如下:

 results_train.append(pool.apply_async(get_batch, args=("train",))) #返回裁剪后的点云信息

在这里插入图片描述
非常需要注意一点的就是图中的callback参数,它也是一个函数名,它的参数来源是第一个函数传来的参数,图中b()函数有返回值,就传递给了callback函数的参数。

注意:其中callback参数是可选的。

3.map()

函数原型:map(func, iterable[, chunksize=None])

Pool类中的map方法,与内置的map函数用法行为基本一致,它会使进程阻塞直到结果返回。
注意:虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程。(输入函数以及参数)

4.close()

关闭进程池(pool),使其不在接受新的任务。

5.join()

主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用。

6.imap_unordered()

其对象有imap()和imap_unordered()方法。

两者都用于对大量数据遍历多进程计算,返回一个迭代器(multiprocessing.pool.IMapIterator)。

imap返回结果顺序和输入相同,imap_unordered则为不保证顺序。

1、iter = pool.imap(fn, data) 一旦生成,无论使不使用iter,多进程计算都会开始。
计算结果会缓存在内存中,所以要注意内存用尽的问题。


Queue()

class queue.Queue(maxsize=0)

FIFO队列的构造函数。maxsize是一个整数,用于设置可以放入队列中的项目数的上限。一旦达到此大小,插入将被阻塞,知道消耗队列项目为止。默认为0,则队列尺寸无限。

Queue.qsize`()
返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞。

Queue.empty()
如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞。

Queue.full()
如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞。

Queue.put(item, block=True, timeout=None)
将 item 放入队列。如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。

Queue.get(block=True, timeout=None)
从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。

Queue.join()
阻塞至队列中所有的元素都被接收和处理完毕。

当条目添加到队列的时候,未完成任务的计数就会增加。每当消费者线程调用 task_done() 表示这个条目已经被回收,该条目所有工作已经完成,未完成计数就会减少。当未完成计数降到零的时候, join() 阻塞被解除。

在线学习文档


Process类

创建一个Process对象然后调用它的 start () 方法来生成进程。一个简单的多进程程序示例是:

from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

代码简单理解:Process ( target = 调用的函数 , args = (‘bob’,)输入参数 )
p.start()生成进程,也就是执行Process函数
p.join()阻塞至进程中所有的元素都被接收和处理完毕。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值