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
相关推荐
柏油5 小时前
MySQL InnoDB 行锁
数据库·后端·mysql
咖啡调调。5 小时前
使用Django框架表单
后端·python·django
白泽talk5 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师5 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
一只叫煤球的猫5 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
Asthenia04126 小时前
HTTP调用超时与重试问题分析
后端
颇有几分姿色6 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
AntBlack6 小时前
别说了别说了 ,Trae 已经在不停优化迭代了
前端·人工智能·后端
@淡 定6 小时前
Spring Boot 的配置加载顺序
java·spring boot·后端