使用方法
- EnterParallelMode()
- CreateParallelContext(“library_name”, “function_name”, nworkers)
- 指定并发数,bgworker拉起几个进程干活。
- shm_toc_estimate_chunk/shm_toc_estimate_keys 评估大小写入pcxt->estimator
- 先评估全部要进入共享内存的大小。
- InitializeParallelDSM(pcxt)
- shm_toc_allocate/shm_toc_insert 写入dsm共享内存
- 对应第3步评估大小,把真实数据插进去,并指定key,子进程用的时候用key查询即可。
- LaunchParallelWorkers(pcxt)
- 拉起bgworker
- worker走ParallelWorkerMain函数启动干活
- 注意ParallelWorkerMain是框架提供的子进程入口函数,会做很多初始化工作。
- 然后调用用户提供的业务逻辑函数,业务逻辑函数由第2步的参数指定。
- 可以指定任意so文件中的函数名,走动态加载找到函数。
- WaitForParallelWorkersToFinish(pcxt)
- DestroyParallelContext(pcxt)
- ExitParallelMode()
注意
- 共享内存:
- bgworker由父进程拉起,与当前进程无任何内存继承关系。进程身份与当前BACKEND对等。
- 基于上述,序列化是并行化最大的工作量,PG已经实现大部分结构体的序列化,大部分可以借鉴。
- nodeToString:序列化
- stringToNode:反序列化
- 锁系统:
- ParallelWorkerMain中会走BecomeLockGroupMember变成锁group leader,注意,这是为了子进程只读的情况下与同一锁组的其他进程不冲突,在只读情况下这是可行的,因为锁组内的行为都是只读的,与锁组外的锁依然会正常互斥。
- 事务系统:
- 子进程启动后,全程处于TBLOCK_PARALLEL_INPROGRESS状态,在现有的实现下,这是一种只读状态,如果需要做读写,需要自己DIY放开事务系统的限制(给子进程起好普通事务用于读写,记得最后让并行框架正常提交)。
- 进程通信
- 使用mq是个很好的选择不用自己实现了,在dsm初始化时顺便分配空间给mq即可,支持阻塞、非阻塞模式;支持flush一般是够用了。
- shm_mq_receive、shm_mq_send