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
相关推荐
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
背水2 小时前
初识Spring
java·后端·spring
晴天飛 雪2 小时前
Spring Boot MySQL 分库分表
spring boot·后端·mysql
weixin_537590452 小时前
《Spring boot从入门到实战》第七章习题答案
数据库·spring boot·后端
AskHarries3 小时前
Spring Cloud Gateway快速入门Demo
java·后端·spring cloud
Qi妙代码3 小时前
MyBatisPlus(Spring Boot版)的基本使用
java·spring boot·后端
宇宙超级勇猛无敌暴龙战神3 小时前
Springboot整合xxl-job
java·spring boot·后端·xxl-job·定时任务
晚睡早起₍˄·͈༝·͈˄*₎◞ ̑̑3 小时前
SpringBoot(五)
java·spring boot·后端