首页 > 其他分享 >ABAP使用异步远程RFC实现并行处理

ABAP使用异步远程RFC实现并行处理

时间:2023-11-15 17:47:34浏览次数:45  
标签:count 异步 jobs gv index RFC ABAP alv --------------------

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秒,效果立竿见影

 

  TRANSLATE with x English
Arabic Hebrew Polish
Bulgarian Hindi Portuguese
Catalan Hmong Daw Romanian
Chinese Simplified Hungarian Russian
Chinese Traditional Indonesian Slovak
Czech Italian Slovenian
Danish Japanese Spanish
Dutch Klingon Swedish
English Korean Thai
Estonian Latvian Turkish
Finnish Lithuanian Ukrainian
French Malay Urdu
German Maltese Vietnamese
Greek Norwegian Welsh
Haitian Creole Persian  
  TRANSLATE with COPY THE URL BELOW Back EMBED THE SNIPPET BELOW IN YOUR SITE Enable collaborative features and customize widget: Bing Webmaster Portal Back     此页面的语言为英语   翻译为中文(简体)        
  • 中文(简体)
  • 中文(繁体)
  • 丹麦语
  • 乌克兰语
  • 乌尔都语
  • 亚美尼亚语
  • 俄语
  • 保加利亚语
  • 克罗地亚语
  • 冰岛语
  • 加泰罗尼亚语
  • 匈牙利语
  • 卡纳达语
  • 印地语
  • 印尼语
  • 古吉拉特语
  • 哈萨克语
  • 土耳其语
  • 威尔士语
  • 孟加拉语
  • 尼泊尔语
  • 布尔语(南非荷兰语)
  • 希伯来语
  • 希腊语
  • 库尔德语
  • 德语
  • 意大利语
  • 拉脱维亚语
  • 挪威语
  • 捷克语
  • 斯洛伐克语
  • 斯洛文尼亚语
  • 旁遮普语
  • 日语
  • 普什图语
  • 毛利语
  • 法语
  • 波兰语
  • 波斯语
  • 泰卢固语
  • 泰米尔语
  • 泰语
  • 海地克里奥尔语
  • 爱沙尼亚语
  • 瑞典语
  • 立陶宛语
  • 缅甸语
  • 罗马尼亚语
  • 老挝语
  • 芬兰语
  • 英语
  • 荷兰语
  • 萨摩亚语
  • 葡萄牙语
  • 西班牙语
  • 越南语
  • 阿塞拜疆语
  • 阿姆哈拉语
  • 阿尔巴尼亚语
  • 阿拉伯语
  • 韩语
  • 马尔加什语
  • 马拉地语
  • 马拉雅拉姆语
  • 马来语
  • 马耳他语
  • 高棉语
 

标签:count,异步,jobs,gv,index,RFC,ABAP,alv,--------------------
From: https://www.cnblogs.com/BinGeneral/p/17834380.html

相关文章

  • 关于SAP ABAP ALV开发的吐槽
    我认为ALV开发时ABAPer第二无聊的工作,非必要千万别做,浪费青春;实在要做也要提高效率少花时间在ALV展示上,集中精力处理后台逻辑。常见的callFM或者OO+Dialog的实现方式,都要手动设置fieldcat、layout,挺烦人的。我比较喜欢用SAP标准的SALV类来做,或者使用国外大神封装的FastAL......
  • element-ui tree 异步树实现勾选自动展开、指定展开、指定勾选
    element-uitree异步树实现勾选自动展开、指定展开、指定勾选 背景项目中用到了vue的element-ui框架,用到了el-tree组件。由于数据量很大,使用了数据懒加载模式,即异步树。异步树采用复选框进行结点选择的时候,没法自动展开,官方文档找了半天也没有找到好的办法!找不到相关的配......
  • Unity-场景的异步加载
    Unity-场景的异步加载为什么需要异步加载​ 在诸多大型游戏里,场景渲染精度都是动态的,随着场景与角色距离的增加,渲染精度也在递减,这样极大的减少了硬件性能的消耗。​ 但如果角色使用了某些传送技能,将自己传送到为渲染的地点,游戏可能就会因为需要瞬间渲染大量的场景而卡顿。此时......
  • 大师学SwiftUI第9章Part 1 - 异步并发之Task、Async、Await和错误
    其它相关内容请见虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记苹果系统借助现代处理器的多核可同步执行多条代码,提升同一时间内程序所能执行的任务。例如,一段代码从网上下载文件,另一段代码可以在屏幕上显示进度。此时,我们不能等待第一个执行完后再执行第二个,而必须要同步执行这......
  • watch和computed的其中一个关键区别就是watch可以执行异步操作,而computed不能执行异步
    下面说法错误的是()Awatch方法中不能执行异步操作B不应该使用箭头函数来定义method函数,箭头函数绑定了父级作用域的上下文,所以this将不会按照期望指向Vue实例CVue实例将会在实例化时调用$watch(),遍历watch对象的每一个propertyDcomputed的结果会被缓存,除非依赖......
  • 异步通讯
    异步调用则可以避免上述问题: 我们以购买商品为例,用户支付后需要调用订单服务完成订单状态修改,调用物流服务,从仓库分配响应的库存并准备发货。在事件模式中,支付服务是事件发布者(publisher),在支付完成后只需要发布一个支付成功的事件(event),事件中带上订单id。订单服务和物流服务......
  • Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmedia
    下列关于Vue的描述错误的是()A当给某个组件修改某个值时,该组件不会立即重新渲染BVue内部使用原生Promise.then、MutationObserver和setImmediate实现异步队列,不会采用setTimeout(fn,0)C$nextTick()返回一个Promise对象D$nextTick()可以配合async/await使用正确答案:B官......
  • 面向对象的 ABAP 里,全局类和局部类有什么区别,以及各自使用场合试读版
    本教程之前的文章,第一次介绍了ABAP面向对象编程领域的类,实例,方法等概念。20.面向对象的ABAP编程初探-什么是类,实例,和Public方法在ABAP很多帮助文档里,我们都能看到SAP在提到类的时候,总是将GlobalClass(全局类)和LocalClass(局部类,有时也称本地类,内部类)相提并论。......
  • ABAP None-Class-Based 异常处理的一些局限性介绍试读版
    本教程前一篇文章,我们已经学习了ABAP里Non-Class-Based异常的使用方法:113.ABAP异常处理(ExceptionHandling)-什么是Non-Class-Based异常从历史上来说,SAPABAP先有Non-Class-Based异常,再有Class-Based异常的解决方案。从道理上分析,前者必定有一些使用上的缺陷,......
  • Vue中的异步更新和 $nextTick
    场景引入需求:当用户点击编辑按钮后,显示一个弹窗,该弹窗有一个文本框,使得文本框自动聚焦看似代码如下:this.isShowEdit=true;//显示输入框this.$refs.inp.focus();//获取焦点代码看似没有问题,显示文本框后,让文本框聚焦,但是在vue中却不能实现,这是由于vue是异步更新Dom的t......