SAP ABAP4 并行处理

在本文中,我想谈谈多线程功能的使用,该功能在许多地方都作为性能拯救了我们。

如果我们必须有序地处理某个数据块,我们在性能方面可能会束手无策。为了说明一个场景,我们可能需要对循环中的记录执行以下操作。

  • 使用 Bapi Ex 读取记录:读取材料的产品树
  • 处理 Excel 行
  • 使用 Bapi 将记录扔进系统

让我们看看如何在这种情况和类似情况下使用我们的救星多线程。基本逻辑是将我们将要执行的操作分成多个部分并并行处理它们。

注意:请勿将此方法用于非常短的操作,因为并行处理的任务管理在 CPU 方面非常耗时。例如,如果您只并行阅读材料的文本,则可能需要更长的时间。

示例场景:为简单起见,让我们编写一个 RFC,该 RFC 返回材料的订单、交货、发票项数。然后,让我们针对每种材料单独并行调用此函数。让我们测量一下他们的工作时间。

步骤 1:RZ12 - RFC 服务器组创建

我建议您从 RZ12 事务代码创建一个 RFC 服务器组。您也可以使用现有的。有关此处参数的详细信息,您可以查看注释527481和 74141。我创建了一个名为 390 的新 RFC 服务器组,如下所示。

步骤 2:RFC 函数

让我们编写一个我们将处理的 RFC(远程启用)。

ABAP 复制代码
FUNCTION zms_material_read.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IV_MATNR) TYPE  MATNR
*"  EXPORTING
*"     VALUE(EV_DELIVERY_ITEMS) TYPE  I
*"     VALUE(EV_INVOICE_ITEMS) TYPE  I
*"     VALUE(EV_ORDER_ITEMS) TYPE  I
*"----------------------------------------------------------------------

    SELECT COUNT(*) INTO ev_delivery_items FROM lips WHERE matnr eq iv_matnr.
    SELECT COUNT(*) INTO ev_invoice_items  FROM vbrp WHERE matnr eq iv_matnr.
    SELECT COUNT(*) INTO ev_order_items    FROM vbap WHERE matnr eq iv_matnr.

ENDFUNCTION.

步骤 3:让我们在程序中使用它

现在我们所要做的就是并行使用空闲的 CPU 任务,并使进程更快地完成。

当我们对 100 种材料执行此操作时;

单例处理 SM50 视图

并行处理 SM50 视图

结果;我们得到的结果比:)快了大约 6 倍我在下面包含了整个程序。

ini 复制代码
REPORT  zms_par.



DATA : gt_matnr     TYPE TABLE OF mara-matnr WITH HEADER LINE,
       gv_completed TYPE i."tamamlanan task lar

CONSTANTS c_pargroup TYPE rfcgr VALUE 'PARTEST'."paralel işleme grubu

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
 PARAMETERS : p_count TYPE i DEFAULT 10.
SELECTION-SCREEN END OF BLOCK b1.

*--------------------------------------------------------------------*
START-OF-SELECTION.
*--------------------------------------------------------------------*

* malzeme listesi
SELECT matnr INTO TABLE gt_matnr FROM mara UP TO p_count ROWS.

* tekil okuma
PERFORM unique_read.
* Paralel okuma
PERFORM parallel_read.

*&---------------------------------------------------------------------*
*&      Form  UNIQUE_READ
*&---------------------------------------------------------------------*
FORM unique_read .

  DATA : lv_time_begin TYPE i,
         lv_time_end   TYPE i,
         lv_time_diff  TYPE i.

  GET RUN TIME FIELD lv_time_begin.
  LOOP AT gt_matnr.
    CALL FUNCTION 'ZMS_MATERIAL_READ'
      EXPORTING
        iv_matnr       = gt_matnr.
  ENDLOOP.
  GET RUN TIME FIELD lv_time_end.

  lv_time_diff = ( lv_time_end - lv_time_begin ) / 1000000.
  WRITE : 'Tekil okuma süresi ', 30 lv_time_diff , ' saniye ...'.

ENDFORM.                    " UNIQUE_READ
*&---------------------------------------------------------------------*
*&      Form  PARALLEL_READ
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM parallel_read .

  DATA : lv_freetask  TYPE i,
         lv_taskname  TYPE char20,
         lv_taskid(8) TYPE n,
         lv_sended    TYPE i,
         lv_completed TYPE i.

*--------------------------------------------------------------------*
* Zaman ölçümü için
  DATA : lv_time_begin TYPE i,
         lv_time_end   TYPE i,
         lv_time_diff  TYPE i.
  GET RUN TIME FIELD lv_time_begin.
*--------------------------------------------------------------------*
  PERFORM get_freetask CHANGING lv_freetask.

  IF lv_freetask GT 1.

    LOOP AT gt_matnr.

      ADD 1 TO lv_taskid.
      CONCATENATE 'T' lv_taskid INTO lv_taskname.
      TRY.
          CALL FUNCTION 'ZMS_MATERIAL_READ'
            STARTING NEW TASK lv_taskname
             DESTINATION IN GROUP c_pargroup
             PERFORMING return_back_this_task
             ON END OF TASK
            EXPORTING
              iv_matnr              = gt_matnr
            EXCEPTIONS
              communication_failure = 1
              system_failure        = 2
              resource_failure      = 3
              error_message         = 4.
              IF sy-subrc <> 0.
                 IF sy-subrc EQ 3.
                   lv_completed  = gv_completed.
                   WAIT UNTIL lv_completed LT gv_completed.
                   CONTINUE.
                 ELSE.
                   ADD 1 TO lv_sended.
                   "hatalı kayıt burada loglanıp tekil işlenmelidir!
                 ENDIF.
              ELSE.
                ADD 1 TO lv_sended.
              ENDIF.
      CATCH cx_root.
         ADD 1 TO lv_sended.
         "hatalı kayıt burada loglanıp tekil işlenmelidir!
      ENDTRY.
    ENDLOOP.
  ELSE.
    PERFORM unique_read."boşta proses yok ise tekil oku
  ENDIF.

  TRY .
      WAIT UNTIL gv_completed EQ lv_sended .
    CATCH cx_root.
      "hatalı kayıt burada loglanıp tekil işlenmelidir!
  ENDTRY.

  GET RUN TIME FIELD lv_time_end.

  lv_time_diff = ( lv_time_end - lv_time_begin ) / 1000000.

  WRITE : / 'Paralel okuma süresi ', 30 lv_time_diff , ' saniye ...'.

ENDFORM.                    " PARALLEL_READ
*&---------------------------------------------------------------------*
*&      Form  return_back_this_task
*&---------------------------------------------------------------------*
FORM return_back_this_task  USING taskname ."#EC CALLED

  DATA ls_mat TYPE bapimatdoa.

  RECEIVE RESULTS FROM FUNCTION 'ZMS_MATERIAL_READ'
*   IMPORTING
*     ........... "sonuçlar burada alınabilir..
   EXCEPTIONS
   resource_failure = 1
   system_failure   = 2
   communication_failure = 3
   OTHERS = 4.

  IF sy-subrc NE 0.
    WRITE : / 'PAR_ERROR' , taskname.
   "hatalı kayıt burada loglanıp tekil işlenmelidir!
  ELSE.
    ADD 1 TO gv_completed.
  ENDIF.

ENDFORM.                    "return_back_this_task
*&---------------------------------------------------------------------*
*&      Form  GET_FREETASK
*&---------------------------------------------------------------------*
FORM get_freetask  CHANGING cv_freetask.

    CALL FUNCTION 'SPBT_INITIALIZE'
      EXPORTING
        group_name                     = c_pargroup
      IMPORTING
        free_pbt_wps                   = cv_freetask
      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.
ENDFORM.

并行处理时 RM_FREE_SESSION_CHECK 进行资源检查

当您需要调用 FM 并选择开始新任务时,始终存在用户已打开最大数量的会话的风险,因此我们的呼叫可能会失败。有一种方法可以避免这种风险 -> 轻松直接调用 FM RM_FREE_SESSION_CHECKTH_USER_INFO 来检查我们是否有能力打开新会话。如果是,那么我们可以在新任务中调用 FM,如果不是,那么我们可以引发错误消息并停止处理我们当前正在执行的函数。当您需要在用户出口内的新任务中调用 FM 时,这非常有用。

ini 复制代码
data: gt_return type bapiret2_tt.   

call function 'RM_FREE_SESSION_CHECK'
      exceptions
        no_free_session = 1
        others          = 2.
    if sy-subrc eq 0.
"Z FM with standard one iside to be able to do commit & rollback
      call function 'Z_BAPI_GOODSMVT_CREATE' 
      starting new task 'NEW_TASK'
       performing check_return on end of task
      exporting
        goodsmvt_header               = fs_goodsmvt_header
        goodsmvt_code                 = fs_goodsmvt_code
        testrun                       = space
*           GOODSMVT_REF_EWM              =
*         IMPORTING
*           GOODSMVT_HEADRET              =
*           MATERIALDOCUMENT              =
*           MATDOCUMENTYEAR               =
      tables
        goodsmvt_item                 = ft_goodsmvt_item
*           GOODSMVT_SERIALNUMBER         =
        return                        = ft_return
*           GOODSMVT_SERV_PART_DATA       =
*           EXTENSIONIN                   =

        .

      wait until g_separatetask_done eq 'X' up to 120 seconds.

    else.
      message e027(14).
*   Maximum number of sessions reached
    endif.

*   Rest of the code goes here

*-----------
* form that is called after task is complete
form check_return using taskname.
  receive results from function 'Z_BAPI_GOODSMVT_CREATE'
  tables
    return = gt_return.
  g_separatetask_done = 'X'.

endform.                    "check_return
相关推荐
程序员大金19 分钟前
基于SSM+Vue+MySQL的酒店管理系统
前端·vue.js·后端·mysql·spring·tomcat·mybatis
程序员大金29 分钟前
基于SpringBoot的旅游管理系统
java·vue.js·spring boot·后端·mysql·spring·旅游
Pandaconda1 小时前
【计算机网络 - 基础问题】每日 3 题(十)
开发语言·经验分享·笔记·后端·计算机网络·面试·职场和发展
程序员大金2 小时前
基于SpringBoot+Vue+MySQL的养老院管理系统
java·vue.js·spring boot·vscode·后端·mysql·vim
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS网上购物商城(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Ylucius2 小时前
JavaScript 与 Java 的继承有何区别?-----原型继承,单继承有何联系?
java·开发语言·前端·javascript·后端·学习
ღ᭄ꦿ࿐Never say never꧂3 小时前
微服务架构中的负载均衡与服务注册中心(Nacos)
java·spring boot·后端·spring cloud·微服务·架构·负载均衡
.生产的驴3 小时前
SpringBoot 消息队列RabbitMQ 消息确认机制确保消息发送成功和失败 生产者确认
java·javascript·spring boot·后端·rabbitmq·负载均衡·java-rabbitmq
海里真的有鱼3 小时前
Spring Boot 中整合 Kafka
后端