在SAP的应用开发中,对于报表的效率是非常重视的。当然优化报表效率的方法有很多,当时当我们遇到需要处理大量数据的报表时会发现用尽所有优化的语句,报表的运行效率还是无法达到用户部门的需求。
下面,我介绍一种方法,也许会对你有所帮助。ABAP的并行处理(原理类似于java的多线程),它是通过RFC接口进行远程函数的异步调用实现程序的并处理。
同步/异步调用函数语法:
同步(sRFC): CALL FUNCTION 'AAA' ;
同步调用的实质:程序进行单线程执行;
异步(aRFC):CALL FUNCTION 'AAA' STARTING NEWTASK "任务名称
DESTINATION IN GROUP
PERFORMING ON END OF TASK。"子程序
异步调用的实质:程序进行多线程执行;
在使用并行处理的过程中通常会遇到如下的可能会发生的问题:
1、重复运行产生的后台任务相互冲突
2、异步调用获取的最终结果与同步调用结果存在差异
3、固定RFC Server Group如system = ‘parallel_generators’,无法保证程序在不同服务器中通用性。
对上述三个问题的解决方法,如下:
1、为了避免后台任务相互冲突,导致输出的数据差异,应确保在相同时间段内同一程序只能被一个用户
占用。所以在开发的程序中添加所对象可以解决。(程序锁的设置,如附件)
2、分析:在LOOP循环中采用异步调用函数的模式,通过SY-SUBRC = 0来判断任务启动成功,
当SY-SUBRC <> 0时,则获取先前启动的进程返回的值,但是这样就遇到一个问题:如第N次循环正好
分配给程序的进程被占用完,这样本次无法启动一个任务进程,导致本次的原始数据通过函数无法获取
目标,从而最终结果出现数据不完整和数值不断变化的现象。
解决:牺牲部分性能保证数据的完整。通过RZ12获取服务器的Max. requests in queue 的值,LOOP
循环的时候统计启动的启动的进程数是否 = Max. requests inqueue,如果等于则获取先前启动的进程
返回的值,然后再重新启动进程,重复此操作。系统分配给每个程序的最大进程数> Max. requests in
queue,但是把启动的进程数限制在Max.requests in queue的水平可以保证获取结果的完整性
3、如何知道系统设置的并行运行进程数呢,通过RZ12,并双击当前登入组,即可以查看到最大并行进程数,
如下图:
一般系统直接指定 =’ parallel_generators ',如上图的“服务器组”对应的内容,为了保持一般性通过如下逻辑段获取:
变量定义-DATA: g_classname Type rzlli_apcl, "Server Group Name
g_applserver Type rzllitab-applserver."RFC Serve Group
取数逻辑- CALL ‘C_SAPGPARAM’ "#EC CI_CCALL
ID ‘NAME’ FIELD ‘rdisp/myname’
ID ‘VALUE’ FIELD g_applserver.
SELECT SINGLE classname
FROM rzllitab
INTO g_classname "Server Group Name
WHERE applserver = g_applserver
AND grouptype = ‘S’. "S:服务器组,空:登陆组
通过上述的描述,可以通过一个实例来串联一下,实例如附件。
1、获取服务组
"获取 RFC Serve Group name Start--*
"一般系统默认g_classname = 'parallel_generators',但为了通用性按照如下方法获取
call 'C_SAPGPARAM' "#EC CI_CCALL
id 'NAME' field 'rdisp/myname'
id 'VALUE' field g_applserver.
select single classname
from rzllitab
into g_classname "Server Group Name
where applserver = g_applserver
and grouptype = 'S'. "S:服务器组,空:登陆组
"获取 RFC Serve Group name End--*
2、异步调用函数
*--优化,异步调用获取数据、
"生成任务名称 = 'Task' + sy-tabix Start--*
move l_tabix to g_taskname.
condense g_taskname.
concatenate 'Task' g_taskname into g_taskname.
"生成任务名称 = 'Task' + sy-tabix End--*
clear: gw_task.
gw_task-matnr = <fs_marc>-matnr.
gw_task-werks = <fs_marc>-werks.
gw_task-dispo = <fs_marc>-dispo.
gw_task-matkl = <fs_marc>-matkl.
gw_task-meins = gw_out-meins.
gw_task-maktx = gw_out-maktx.
gw_task-labst = gw_out-labst.
gw_task-taskname = g_taskname.
append gw_task to gt_task.
* 异步调用函数 Start--*
call function 'BAPI_MATERIAL_STOCK_REQ_LIST' starting new task g_taskname
destination in group g_classname
performing frm_subroutine_done on end of task "子程序
* 只要将函数的EXPORTING参数放在此处,其他参数放到子程序中
exporting
material = <fs_marc>-matnr
plant = <fs_marc>-werks
get_item_details = 'X'
get_ind_lines = 'X'
* 系统标准报错信息
exceptions
communication_failure = 1 message mess
system_failure = 2 message mess
resource_failure = 3.
if sy-subrc = 0.
snd_jobs = snd_jobs + 1.
endif.
* 异步调用函数 End--*
open_task_num = open_task_num + 1. "记录启动的进程数量
if open_task_num = pnum.
* 获取并发进程返回的结果
wait until rcv_jobs >= snd_jobs.
clear:open_task_num,rcv_jobs,snd_jobs.
free:gt_task.
else.
if l_tabix = l_lines.
* 获取并发进程返回的结果
wait until rcv_jobs >= snd_jobs.
clear:open_task_num,rcv_jobs,snd_jobs.
free:gt_task.
endif.
endif.
3、处理子例程
rcv_jobs = rcv_jobs + 1. ""Receiving data
receive results from function 'BAPI_MATERIAL_STOCK_REQ_LIST'
tables
mrp_items = gt_mrp_items.
read table gt_task into gw_task with key taskname = g_taskname binary search.
if sy-subrc eq 0.
转载来自:
https://www.cnblogs.com/qlb8268/p/3606061.html
https://blog.csdn.net/zhongguomao/article/details/8963815
https://blog.csdn.net/wangjolly/article/details/8949754