SAP ABAP4 并行处理

举报
雨绸缪 发表于 2023/10/30 16:19:02 2023/10/30
【摘要】 在本文中,我想谈谈多线程功能的使用,该功能在许多地方都作为性能拯救了我们。如果我们必须有序地处理某个数据块,我们在性能方面可能会束手无策。为了说明一个场景,我们可能需要对循环中的记录执行以下操作。使用 Bapi Ex 读取记录:读取材料的产品树处理 Excel 行使用 Bapi 将记录扔进系统让我们看看如何在这种情况和类似情况下使用我们的救星多线程。基本逻辑是将我们将要执行的操作分成多个部分...

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

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

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

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

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

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

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

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

Snipaste_2023-09-07_17-13-34.png

步骤 2:RFC 函数

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

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 种材料执行此操作时;

image.png

单例处理 SM50 视图

image.png

并行处理 SM50 视图

image.png

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

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 时,这非常有用。

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
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。