1、使用场景

当开发复杂报表,需要处理大量数据,不管怎么优化计算和查询语句,程序的运行效率还是达不到用户要求,怎么办?

为了解决这个问题,就需要程序实现并行处理。

本文档就是通过异步调用远程RFC的办法,实现对大量数据的计算,以并行的方式,更快的计算出最终结果。

2、代码实现

在实现并行处理时,首先要看系统当前能并行的资源数

"--------------------@斌将军--------------------
"获取服务器标识
CALL 'C_SAPGPARAM'
ID 'NAME' FIELD 'rdisp/myname'
ID 'VALUE' FIELD gv_applserver. "获取登录/服务器组名称
SELECT SINGLE
classname
FROM rzllitab
INTO gv_classname "Server Group Name
WHERE applserver = gv_applserver
AND grouptype = 'S' . "S:服务器组,空:登陆组 CALL FUNCTION 'SPBT_INITIALIZE'
EXPORTING
group_name = gv_classname
IMPORTING
max_pbt_wps = gv_total "可用资源总数
free_pbt_wps = gv_available "空闲资源数
EXCEPTIONS
invalid_group_name = 1
internal_error = 2
pbt_env_already_initialized = 3
currently_no_resources_avail = 4
no_pbt_resources_found = 5
cant_init_different_pbt_groups = 6
OTHERS = 7.
"--------------------@斌将军--------------------

将逻辑处理封装为远程RFC,比如现在要计算1000行数据,每行数据乘以一百万次循环的累加数,然后展示出结果。远程RFC的计算逻辑如下:

"--------------------@斌将军--------------------
FUNCTION ytest001_001.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" VALUE(I_INDEX) TYPE I
*" VALUE(I_COUNT) TYPE I
*" EXPORTING
*" VALUE(E_INDEX) TYPE I
*" VALUE(E_COUNT) TYPE I
*"---------------------------------------------------------------------- DO 1000000 TIMES.
i_count = i_count + 1.
ENDDO. i_count = i_count * i_index. e_index = i_index.
e_count = i_count. ENDFUNCTION.
"--------------------@斌将军--------------------

在主程序中调用远程RFC,并且添加远程调用的系统报错异常communication_failure和system_failure

"--------------------@斌将军--------------------
CALL FUNCTION 'YTEST001_001' STARTING NEW TASK gv_taskname
DESTINATION IN GROUP gv_classname
PERFORMING frm_ytest ON END OF TASK "调用每条线程的处理方法,接收处理结果
EXPORTING
i_index = ps_alv-index
i_count = ps_alv-count
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message
resource_failure = 3.
"--------------------@斌将军--------------------

并在主程序中接收远程RFC的返回消息

"--------------------@斌将军--------------------
"返回消息处理
FORM frm_ytest USING taskname. DATA:ls_alv TYPE ty_alv. "接收处理数据的返回消息
RECEIVE RESULTS FROM FUNCTION 'YTEST001_001'
IMPORTING
e_index = ls_alv-index
e_count = ls_alv-count
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message. MODIFY gt_alv FROM ls_alv TRANSPORTING count WHERE index = ls_alv-index. "已完成进程 + 1
gv_end_jobs = gv_end_jobs + 1.
ENDFORM.
"--------------------@斌将军--------------------

完整参考代码:

"--------------------@斌将军--------------------
TYPES:BEGIN OF ty_alv,
index TYPE i,
count TYPE i,
END OF ty_alv. DATA:gt_alv TYPE TABLE OF ty_alv,
gs_alv TYPE ty_alv. DATA:gv_open_jobs TYPE i, "开启的进程
gv_jobs TYPE i, "可用的进程
gv_end_jobs TYPE i. "结束的进程 DATA:gv_applserver TYPE rzlli_asvr, "服务器标识 实例名称(用于登录/服务器组分配)
gv_classname TYPE rzlli_apcl, "登录/服务器组名称
gv_taskname TYPE char10, "进程名称
gv_init_flag TYPE char1,
gv_total TYPE i, "可用资源总数
gv_available TYPE i. "空闲资源数 DATA:lv_count TYPE i,
lv_flat TYPE p DECIMALS 2,
lv_message TYPE char200. "准备1000行测试数据
DO 1000 TIMES.
gs_alv-index = sy-index.
gs_alv-count = 1.
APPEND gs_alv TO gt_alv.
ENDDO. "获取服务器标识
PERFORM frm_get_server. "获取服务器组对应的可用资源数
PERFORM frm_get_jobs_available. "处理每行数据,实际应用时,看如何将数据“分批”
CLEAR:lv_count.
LOOP AT gt_alv INTO gs_alv. lv_count = lv_count + 1."进程任务计数器
IF gv_open_jobs - gv_end_jobs = gv_jobs."已开进程 - 已结束进程 = 可用进程
WAIT UNTIL gv_open_jobs - gv_end_jobs < gv_jobs."等待 已开进程 - 已结束进程 < 可用进程
ENDIF. "拼接进程名称
gv_taskname = 'Task' && lv_count.
CONDENSE gv_taskname. "逻辑处理
PERFORM frm_deal_task USING gs_alv.
CLEAR:gs_alv.
ENDLOOP. "等待所有的进程执行完毕
WAIT UNTIL gv_end_jobs >= gv_open_jobs. "展示结果
CALL METHOD cl_demo_output=>display
EXPORTING
data = gt_alv. *&---------------------------------------------------------------------*
*& Form FRM_GET_SERVER
*&---------------------------------------------------------------------*
* text 获取服务器标识
*----------------------------------------------------------------------*
FORM frm_get_server.
"获取服务器标识
CALL 'C_SAPGPARAM'
ID 'NAME' FIELD 'rdisp/myname'
ID 'VALUE' FIELD gv_applserver. "获取登录/服务器组名称
SELECT SINGLE
classname
FROM rzllitab
INTO gv_classname "Server Group Name
WHERE applserver = gv_applserver
AND grouptype = 'S' . "S:服务器组,空:登陆组 ENDFORM. *&---------------------------------------------------------------------*
*& Form FRM_GET_JOBS_AVAILABLE
*&---------------------------------------------------------------------*
* text 获取服务器组对应的可用资源数
*----------------------------------------------------------------------*
FORM frm_get_jobs_available. gv_jobs = 0."可用资源数
IF gv_init_flag IS INITIAL."第一次获取资源
"资源查询 - 获取最多jobs 个数
CALL FUNCTION 'SPBT_INITIALIZE'
EXPORTING
group_name = gv_classname
IMPORTING
max_pbt_wps = gv_total "可用资源总数
free_pbt_wps = gv_available "空闲资源数
EXCEPTIONS
invalid_group_name = 1
internal_error = 2
pbt_env_already_initialized = 3
currently_no_resources_avail = 4
no_pbt_resources_found = 5
cant_init_different_pbt_groups = 6
OTHERS = 7. CASE sy-subrc.
WHEN 0.
lv_flat = gv_available * 9 / 10.
gv_jobs = floor( lv_flat ). "拿其中一部分的空闲资源数来执行
IF gv_jobs = 0 AND gv_available = 1.
gv_jobs = 1.
ENDIF.
gv_init_flag = 'X'.
"按照jobs来进行数据拆分
WHEN 1.
* MESSAGE E836."未定义 PBT 服务器组
WHEN 2. WHEN 3.
* MESSAGE E833."已为组初始化了 PBT 环境
WHEN 4.
* MESSAGE E837."所有服务器正忙:没有可用的资源
WHEN 5.
WHEN 6.
ENDCASE. "刷新资源数量
ELSE.
"第二次获取资源调用函数
CALL FUNCTION 'SPBT_GET_CURR_RESOURCE_INFO'
IMPORTING
max_pbt_wps = gv_total
free_pbt_wps = gv_available
EXCEPTIONS
internal_error = 1
pbt_env_not_initialized_yet = 2
OTHERS = 3.
CASE sy-subrc .
WHEN 0.
lv_flat = gv_available * 9 / 10.
gv_jobs = floor( lv_flat ). "拿其中一部分的空闲资源数来执行
IF gv_jobs = 0 AND gv_available = 1.
gv_jobs = 1.
ENDIF.
WHEN 1.
WHEN 2.
CLEAR gv_init_flag.
PERFORM frm_get_jobs_available. "获取失败则递归调用
WHEN 3.
ENDCASE.
ENDIF.
ENDFORM. " FRM_GET_JOBS_AVAILABLE *&---------------------------------------------------------------------*
*& Form FRM_DEAL_TASK
*&---------------------------------------------------------------------*
* text 逻辑处理
*----------------------------------------------------------------------*
FORM frm_deal_task USING ps_alv TYPE ty_alv. "调用需要并行执行的函数,此函数必须为远程函数
CALL FUNCTION 'YTEST001_001' STARTING NEW TASK gv_taskname
DESTINATION IN GROUP gv_classname
PERFORMING frm_ytest ON END OF TASK "调用每条进程的处理方法,接收处理结果
EXPORTING
i_index = ps_alv-index
i_count = ps_alv-count
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message
resource_failure = 3. IF sy-subrc = 0.
gv_open_jobs = gv_open_jobs + 1. "开启进程成功,则已开启变量 + 1
ELSEIF sy-subrc = 3.
WAIT UP TO '0.1' SECONDS.
WAIT UNTIL gv_open_jobs - gv_end_jobs < gv_jobs."等待 已开进程 - 已结束进程 < 可用进程
PERFORM frm_deal_task USING ps_alv."递归调用,重复开启进程
ELSE.
* WRITE: sy-index,sy-subrc,lv_message.
ENDIF.
ENDFORM. *&---------------------------------------------------------------------*
*& Form FRM_YTEST
*&---------------------------------------------------------------------*
* text 返回消息处理
*----------------------------------------------------------------------*
FORM frm_ytest USING taskname. DATA:ls_alv TYPE ty_alv. "接收处理数据的返回消息
RECEIVE RESULTS FROM FUNCTION 'YTEST001_001'
IMPORTING
e_index = ls_alv-index
e_count = ls_alv-count
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message. MODIFY gt_alv FROM ls_alv TRANSPORTING count WHERE index = ls_alv-index. "已完成进程 + 1
gv_end_jobs = gv_end_jobs + 1.
ENDFORM.
"--------------------@斌将军--------------------

3、效率对比

常规处理方式的代码:

"--------------------@斌将军--------------------
LOOP AT gt_alv INTO gs_alv.
CALL FUNCTION 'YTEST001_001'
EXPORTING
i_index = gs_alv-index
i_count = gs_alv-count
IMPORTING
e_index = gs_alv-index
e_count = gs_alv-count.
MODIFY gt_alv FROM gs_alv TRANSPORTING count WHERE index = gs_alv-index.
ENDLOOP.
"--------------------@斌将军--------------------

耗时对比

并行处理耗时1.7秒,常规处理耗时172秒,效果立竿见影

定期更文,欢迎关注

 
 
 
 
 
此页面的语言为英语
 
翻译为中文(简体)
 
 
 
 
  • 中文(简体)
  • 中文(繁体)
  • 丹麦语
  • 乌克兰语
  • 乌尔都语
  • 亚美尼亚语
  • 俄语
  • 保加利亚语
  • 克罗地亚语
  • 冰岛语
  • 加泰罗尼亚语
  • 匈牙利语
  • 卡纳达语
  • 印地语
  • 印尼语
  • 古吉拉特语
  • 哈萨克语
  • 土耳其语
  • 威尔士语
  • 孟加拉语
  • 尼泊尔语
  • 布尔语(南非荷兰语)
  • 希伯来语
  • 希腊语
  • 库尔德语
  • 德语
  • 意大利语
  • 拉脱维亚语
  • 挪威语
  • 捷克语
  • 斯洛伐克语
  • 斯洛文尼亚语
  • 旁遮普语
  • 日语
  • 普什图语
  • 毛利语
  • 法语
  • 波兰语
  • 波斯语
  • 泰卢固语
  • 泰米尔语
  • 泰语
  • 海地克里奥尔语
  • 爱沙尼亚语
  • 瑞典语
  • 立陶宛语
  • 缅甸语
  • 罗马尼亚语
  • 老挝语
  • 芬兰语
  • 英语
  • 荷兰语
  • 萨摩亚语
  • 葡萄牙语
  • 西班牙语
  • 越南语
  • 阿塞拜疆语
  • 阿姆哈拉语
  • 阿尔巴尼亚语
  • 阿拉伯语
  • 韩语
  • 马尔加什语
  • 马拉地语
  • 马拉雅拉姆语
  • 马来语
  • 马耳他语
  • 高棉语
 
随时将英语翻译为中文(简体)PRO
一律不翻译英语
一律不翻译i.cnblogs.com

ABAP使用异步远程RFC实现并行处理的更多相关文章

  1. ABAP 调用远程rfc

    ABAP 调用rfc DESTINATION附加项后面接的是远程目标名称,该目标在事务SM59中设定,其中包含连接和登录远程系统所需的全部参数信息.如果调用的就是本机的RFC目标,则DESTINATI ...

  2. 跟踪记录ABAP对外部系统的RFC通信

    对SAP系统而言,RFC最常见的系统间通信方式,SAP与SAP系统及SAP与非SAP系统之间的连接都可以使用它.它的使用便利,功能强大,在各种接口技术中,往往是最受(ABAP开发者)青睐的选择. 查询 ...

  3. ABAP RFC远程调用

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  4. [SAP ABAP开发技术总结]Function远程、同步、异步调用

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  5. SAP RFC通信模式

    在网络技术中,数据通信可以大致划分为两种基本模式:同步通信和异步通信. 其本义是:异步通信时,通信双方时钟允许存在一定误差:同步通信时,双方时钟的允许误差较小.在SAP的系统间的通信过程中,也借用术语 ...

  6. SAP RFC函数

    RFC 接口 RFC是对一个函数模块的调用,但是调用者的系统与被调函数所在的系统是不一样的. RFC也可以在系统内被调用,但是通常调用和被调用是在不同的系统中的. 在sap系统中,远程调用的能力是有R ...

  7. 异步JS:$.Deferred的使用

    异步JS:$.Deferred的使用 原文链接:http://www.html5rocks.com/en/tutorials/async/deferred/ 当我们构建一个平稳的,响应式的HTML5应 ...

  8. Openstack Nova 源码分析 — RPC 远程调用过程

    目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...

  9. PA教材提纲 TAW10-1

    Unit1 SAP systems(SAP系统) 1.1 Explain the Key Capabilities of SAP NetWeaver(解释SAP NetWeaver的关键能力) Rep ...

  10. Java(JCo3)与SAP系统相互调用

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

随机推荐

  1. 微信小程序动态生成表单来啦!你再也不需要手写表单了!

    dc-vant-form 由于我们在小程序上涉及到数据采集业务,需要经常使用表单,微信小程序的表单使用起来非常麻烦,数据和表单是分离的,每个输入框都需要做数据处理才能实现响应式数据,所以我开发了dc- ...

  2. UIPath变量和参数

    一. UIPath变量   变量(Variables),变量是所有编程语言中必不可少的部分.对于UIPath来说自然也是如此,其承载了我们RPA流程中数据传递的重要作用.对于接触过编程的开发者来说,变 ...

  3. Kepware楼宇自控BACnet/IP驱动

    BACnet/IP驱动是楼宇自动化设备驱动的集合,为用户提供一种方便快捷的楼宇自动化设备数采解决方案.只需要通过简单的配置就可以将常见的BACnet/IP协议设备无缝连接到 HMI/SCADA.MES ...

  4. 【Javaweb】动态web工程目录介绍

    src 存放自己编写的Java源代码 web 专门用来存放web工程的资源文件(html页面.css文件.js文件等等) WEB-INF 是一个受服务器保护的目录,浏览器无法直接访问此目录的内容 we ...

  5. Android的内部存储和外部存储怎么区分?

    1.定义 内部存储:内部存储位于Android手机系统的data/data/<包名>这个目录下,内部存储是私有的,主要用于存储系统和应用程序的某些数据,对于其他应用程序来说是不可见的,并且 ...

  6. erp——绩效考核系统——软件需求规格说明书

    绩效考核系统--软件需求规格说明书 引言 1.1编写目的:此文件需求说明书主要是为了开发人员能了解系统之间的关系,使用者能明白系统的使用方法,另外,可以供一些学习的小白进行参考,提供需要的人参考软件需 ...

  7. Http请求超好用的工具类

    话题不多说,直接开整 1.先导入依赖 <dependency> <groupId>io.github.admin4j</groupId> <artifactI ...

  8. 三维GIS渲染引擎盘点,以Cesium为核心的拓展优化

    目前,以Cesium为核心的各类产品繁多,本文将挑选一些以Cesium为核心的软件案例,为大家进行介绍. 1. CesiumJS CesiumJS相信凡是GIS行业相关人员都特别熟悉了,CesiumJ ...

  9. modeless dialog in html

    <!DOCTYPE html> <html lang="zh_CN"> <head> <meta charset="UTF-8& ...

  10. IOS关闭锁屏状态下左滑相机

    IOS 锁屏状态下,左滑就会打开相机,还不能关闭.这种功能说真的,没有啥用,还很麻烦.看了一圈教程,写的也是没写全.自己再写一个,以后换手机还用得上. 注:此方法会导致微信的扫一扫不可用 1.找到&q ...