IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 对ABAP程序调优的学习(三)并发读取 -> 正文阅读

[大数据]对ABAP程序调优的学习(三)并发读取

该篇文章详细介绍用SAP ABAP 并发读取功能解决数据读取慢的问题。

博主有一个场景,在APO模块中读取生产订单和相关的配置、BOM数据,是依赖于SAP的标准函数:/SAPAPO/OM_ORDER_GET_DATA,这个函数后面就是HANA数据库的存储过程,直接在APO LiveCache中读取订单数据。

一直以来,我们都觉得这个点上,没有办法再优化了,直到我看到了SAP帮助中的异步RFC说明

经过测试,/SAPAPO/OM_ORDER_GET_DATA函数读取100个订单数据的时间是250秒,差不多一个需要耗时2~3秒,如果把它封装到一个RFC函数中,然后打开多个函数,一次只读一个订单,但是并发执行,速度是非常快的,快到只需要几秒就完成100个订单的数据收集,几乎可以说没有耗时。

一、首先,我们看看封装的函数:

1、输入参数

2、输出数据表:

??

3、函数代码:

?二、然后是我们发起并发的主程序:

*&---------------------------------------------------------------------*
*& Report ZJAMES_L001
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZJAMES_L005.

DATA:

    table_ordid   TYPE /sapapo/om_tab_ordid,
    gv_ordid      type /SAPAPO/OM_ORDERUID.

DATA:
  g2_ordkeys      TYPE /sapapo/om_ordkey_tab,               "#EC NEEDED
  g2_activities   TYPE /sapapo/om_tab_act,                  "#EC NEEDED
  g2_inputs       TYPE /sapapo/om_io_tab,                "#EC NEEDED
  g2_outputs      TYPE /sapapo/om_io_tab.                "#EC NEEDED


SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-t01.


SELECT-OPTIONS:
  s_m FOR gv_ordid.


SELECTION-SCREEN END  OF BLOCK b1.



LOOP AT s_m INTO DATA(gs54).

   APPEND gs54-LOW TO table_ordid.

 ENDLOOP.


"---------2022.6.18 ---james_lx-----begin----------

  DATA: gv_i      TYPE i VALUE 0,
        snd_jobs  TYPE i VALUE 0,
        rcv_jobs  TYPE i VALUE 0,
        name(20)   TYPE c ,
        exc_flag  TYPE i.


DO 100 TIMES.



LOOP AT table_ordid INTO DATA(wa).

      gv_i = gv_i + 1.

      IF ( gv_i MOD 30 ) = 0 .
            WAIT UNTIL rcv_jobs >= snd_jobs.
      ENDIF.

      name = 'Task' && gv_i.

      CALL FUNCTION 'ZRFC_ORDER_GET_DATA'
        STARTING NEW TASK name
        DESTINATION IN GROUP DEFAULT
        PERFORMING callbback_meth ON END OF TASK

        EXPORTING
          IV_ORDID  = wa
        EXCEPTIONS
          system_failure        = 1
          communication_failure = 2
          resource_failure      = 3.

       CASE sy-subrc.
         WHEN 0.
           snd_jobs = snd_jobs + 1.
         WHEN 1 OR 2.

         WHEN 3.
           IF snd_jobs >= 1 AND exc_flag = 0.
              exc_flag = 1.
             WAIT UNTIL rcv_jobs >= snd_jobs.
           ENDIF.

           IF sy-subrc = 0.
             exc_flag = 0.
           ELSE.

           ENDIF.
         WHEN OTHERS.


       ENDCASE.


ENDLOOP.



    WAIT UNTIL rcv_jobs >= snd_jobs .



    WRITE:

    /'------------',name && ',' && SY-DATUM && ',' && SY-TIMLO,'-------------------',
    /'gt_ordkeys行数:' , lines( g2_ORDKEYS ) ,
    /'gt_act行数:'    ,  lines( g2_ACTIVITIES ) ,
    /'gt_inputs行数:' ,  lines( g2_INPUTS ) ,
    /'gt_outputs行数:' , lines( g2_OUTPUTS ).


    if lines( g2_ordkeys ) <> lines( table_ordid ) .
        WRITE:/ '并行读取后,验证失败,系统繁忙!'.
     ENDIF.


    REFRESH g2_ORDKEYS[].
    REFRESH g2_ACTIVITIES[].
    REFRESH g2_INPUTS[].
    REFRESH g2_OUTPUTS[].

ENDDO.




FORM callbback_meth USING name.


   DATA:  lt_ordkeys      TYPE /sapapo/om_ordkey_tab,
          lt_activities   TYPE /sapapo/om_tab_act,
          lt_inputs       TYPE /sapapo/om_io_tab,
          lt_outputs      TYPE /sapapo/om_io_tab.


    REFRESH lt_ORDKEYS[].
    REFRESH lt_ACTIVITIES[].
    REFRESH lt_INPUTS[].
    REFRESH lt_OUTPUTS[].


    RECEIVE RESULTS FROM FUNCTION 'ZRFC_ORDER_GET_DATA'
        TABLES
          EGT_ORDKEYS         =  lt_ORDKEYS
          EGT_ACTIVITIES      =  lt_ACTIVITIES
          EGT_INPUTS          =  lt_INPUTS
          EGT_OUTPUTS         =  lt_OUTPUTS.



    append lines of lt_ORDKEYS    to g2_ORDKEYS.
    append lines of lt_ACTIVITIES to g2_ACTIVITIES.
    append lines of lt_INPUTS     to g2_INPUTS.
    append lines of lt_OUTPUTS    to g2_OUTPUTS.

    rcv_jobs = rcv_jobs + 1.

  ENDFORM.


这里有几点说明:

1、?WAIT?UNTIL?rcv_jobs?>=?snd_jobs?. 只是存在并发RFC代码的回调函数时生效,调试程序执行顺序可以看到,先主函数,然后检查WAIT UNTIL条件,最后调用回调函数。

2、为了确保主函数发出的函数调用,都可以在回调函数中收回来,会有一个TASK NAME来标记,如果数据比较大,这个NAME字段要定义长一点,而SAP标准例子DEMO_PARALLEL_RFC中,只给了4位,只能处理9999次RFC,这样会在数据超出后造成混乱。博主一开始以为是SAP不支持线程安全的问题,因为ABAP中确实没有C#中的线程安全对象和操作符,甚至连是不是线程都说不上,因为RFC的工作是靠DIA工作进程,而一个DIA工作进程可以被dispatch分配5个任务,这里也没有看到有线程的明确说明,不过看起来,RFC的多次调用应该是使用了多线程。

3、主函数中加入了一次并发的数量限制代码:

IF?(?gv_i?MOD?30?)?=?0?.
????????????WAIT?UNTIL?rcv_jobs?>=?snd_jobs.
??????ENDIF.

它的意思是,虽然我们的任务可能有300次,但主函数每一次只放30个RFC出去,完成后,再放30个RFC去执行,虽然是30个一批,但其实效率也是非常的高,因为也没有什么延时停顿什么的,可以说是发挥了服务器最佳性能。30个的数量,可以参考SM50中DIA的数量,博主的服务器有50个DIA。(写道这里居然想到侯杰的《深入浅出MFC》中描写多线程是像猛虎一样的冲出来。。。)

压力测试中的RFC并发:

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-06-20 23:03:25  更:2022-06-20 23:04:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 0:18:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码