SAP ABAP程序优化-多线程并行处理

转载请标明出处:http://blog.csdn.net/wanglei880526/article/details/8949754

实际项目实施过程中,我们会遇到程序性能优化的问题,这里介绍一种方法:通过RFC接口进行远程函数的异步调用实现程序的并行处理。

   同步/异步调用函数语法

同步调用:CALL FUNCTION 'AAA' ;

同步调用的实质:程序进行单线程执行。

异步调用:CALL FUNCTION 'AAA' STARTING NEWTASK  "任务名称

DESTINATION IN GROUP 

                         PERFORMING ON END OF TASK"子程序

    异步调用的实质:程序进行多线程执行。

一些关于函数异步调用实现程序并行处理的文章,没有介绍如下问题:

⒈ 为了避免相同程序重复运行产生的后台任务相互冲突,需要保证在相同时间段同一程序只被一个用户占用;

⒉ 异步调用获取的最终结果数据与同步调用获取的结果存在差异;

⒊ 固定RFC Server Group如system 'parallel_generators'无法保证程序在不同服务器中通用性。

问题1分析:从MD01中运行MRP我们可以知道,系统为了避免相同程序并发执行,导致后台任务冲突, MD01在并行模式下是不允许被两个用户同时执行的。如下图

SAP ABAP程序优化-多线程并行处理_第1张图片


解决方法:通过在程序中利用锁对象来达到程序相同时间段只被同一用户占用的目的。


问题2分析:在LOOP循环中采用异步调用函数的模式,通过SY-SUBRC = 0来判断任务启动成功,当SY-SUBRC <> 0时,则获取先前启动的进程返回的值,但是这样就遇到一个问题:如第N次循环正好分配给程序的进程被占用完,这样本次无法启动一个任务进程,导致本次的原始数据通过函数无法获取目标,从而最终结果出现数据不完整和数值不断变化的现象。

解决方法 :牺牲部分性能保证数据的完整。通过RZ12获取服务器的Max. requests in queue 的值,LOOP循环的时候统计启动的启动的进程数是否 = Max. requests inqueue,如果等于则获取先前启动的进程返回的值,然后再重新启动进程,重复此操作。系统分配给每个程序的最大进程数> Max. requests in queue,但是把启动的进程数限制在Max.requests in queue的水平可以保证获取结果的完整性。如下图所示

SAP ABAP程序优化-多线程并行处理_第2张图片


问题3分析:一般系统直接指定 =' parallel_generators ',如上图的“服务器组”对应的内容,为了保持一般性通过如下逻辑段获取

CALL 'C_SAPGPARAM'  "#EC CI_CCALL                     ID 'NAME'  FIELD 'rdisp/myname'
    ID 'VALUE' FIELD g_applserver.  "
  SELECT SINGLE classname
    FROM rzllitab
    INTO g_classname   "Server Group Name
    WHERE applserver = g_applserver
    AND grouptype = 'S'.   "S:服务器组,空:登陆组


下面通过例子来说明函数异步调用,这里使用函数        

 'MD_STOCK_REQUIREMENTS_LIST_API'获取MD04中的物料+工厂 MRP数据明细。首先我们使用同步调用的方法,然后再使用异步调用的方法,比较二者在同等条件下的执行效率。

(假设需求:从物料工厂表MARC中获取一定的行项目,这里设定为18000条,然后通过调用函数获取物料工厂对应的MRP清单,将物料工厂与获取的对应清单整合输出)

同步调用:(完整程序在程序最后)

select matnr werks

    UP TO 18000 ROWS               "数据条目18000
    INTO CORRESPONDING FIELDS OF TABLE it_marc
    FROM marc
    WHERE matnr IN s_matnr
    AND   werks IN s_werks.
 
  LOOP AT it_marc INTO wa_marc.
    CLEAR it_md.
    CALL FUNCTION  'MD_STOCK_REQUIREMENTS_LIST_API'
      EXPORTING
        MATNR                    = wa_marc-matnr
        WERKS                    = wa_marc-werks
      TABLES
        MDEZX                    = it_md
      EXCEPTIONS
        MATERIAL_PLANT_NOT_FOUND = 1
        PLANT_NOT_FOUND          = 2
        OTHERS                   = 3.
 
    LOOP AT it_md INTO wa_md.
      MOVE-CORRESPONDING wa_md TO wa_output.
      wa_output-matnr = wa_marc-matnr.
      wa_output-werks = wa_marc-werks.
      APPEND wa_output TO it_output.
      CLEAR:wa_output,wa_md.
    ENDLOOP.
    CLEAR wa_marc.
  ENDLOOP.

很显然在同步执行情况下,只有一个进程是执行我们调用的函数,其他的进程处于idle状态。


异步调用

解决问题1:为了达到当前用户可以独占程序,进入选择界面即锁定程序:

AT SELECTION-SCREEN.
  "锁定程序
  CALL FUNCTION 'ENQUEUE_EZZSOPR0032'
    EXPORTING
      mode_trdir     = 'E'         "锁类型
      name           = 'ZSOPR0032' "锁对象名称
      x_name         = ' '
      _scope         = '2'
      _wait          = ' '
      _collect       = ' '
    EXCEPTIONS
      foreign_lock   = 1
      system_failure = 2
      OTHERS         = 3.
  IF sy-subrc <> 0.
    MESSAGE '对象已被锁定,请稍后执行' TYPE 'E'.
  ENDIF.

解决问题1:当程序异步调用函数的操作结束后,即可接触对程序的锁定:

END OF SELECTION.
  "解除程序的锁定
  CALL FUNCTION 'DEQUEUE_EZZSOPR0032'
    EXPORTING
      mode_trdir = 'E'
      name       = 'ZSOPR0032'
      x_name     = ' '
      _scope     = '3'
      _synchron  = ' '
      _collect   = ' '.

 

解决问题3:获取RFC Serve Group name

获取 RFC Serve Group name         Start--*
* 一般系统默认g_classname = 'parallel_generators',但为了通用性按照如下方法获取
  CALL 'C_SAPGPARAM'                                      "#EC CI_CCALL
    ID 'NAME'  FIELD 'rdisp/myname'
    ID 'VALUE' FIELD g_applserver.
 
  SELECT SINGLE classname
    FROM rzllitab
    INTO g_classname   "Server Group Name
    WHERE applserver = g_applserver
    AND grouptype = 'S'.   "S:服务器组,空:登陆组
获取 RFC Serve Group name         End--*

 

解决问题2:通过 最大请求队列的值 来控制启动进程数

SELECT matnr werks

    UP TO 18000 ROWS               "数据条目18000
    INTO CORRESPONDING FIELDS OF TABLE it_marc
    FROM marc
    WHERE matnr IN s_matnr
AND   werks IN s_werks.
 

LOOP AT it_marc INTO wa_marc.

*   生成任务名称 = 'Task' + sy-tabix  Start--*

    WRITE sy-tabix TO g_taskname.

    CONDENSE g_taskname.

    CONCATENATE 'Task' g_taskname INTO g_taskname.

*   生成任务名称 = 'Task' + sy-tabix   End--*

    lw_marc-taskname = g_taskname.

    lw_marc-matnr = wa_marc-matnr.

    lw_marc-werks = wa_marc-werks.

    APPEND wa_marc TO lt_marc.

*   异步调用函数    Start--*

    CALL FUNCTION 'MD_STOCK_REQUIREMENTS_LIST_API' STARTINGNEW TASK g_taskname

        DESTINATION INGROUPg_classname

        PERFORMING frm_subroutine_done ONEND OF TASK"子程序

*      只要将函数的EXPORTING参数放在此处,其他参数放到子程序中

        EXPORTING

          matnr                 = wa_marc-matnr

          werks                 = wa_marc-werks

*       系统标准报错信息

        EXCEPTIONS

          communication_failure = 1  MESSAGE mess

          system_failure        = 2 MESSAGE mess

          resource_failure      = 3.

        IF sy-subrc = 0.

          snd_jobs = snd_jobs + 1.

        ENDIF.

*   异步调用函数     End--*

    open_task_num = open_task_num + 1.   "记录启动的进程数量

    IF open_task_num = p_wp.    "p_wp = RZ12中的 Max. requests in queue

*    获取并发进程返回的结果

      WAIT UNTIL rcv_jobs >= snd_jobs.

      CLEAR:open_task_num,rcv_jobs,snd_jobs.

      FREE:lt_marc.

    ENDIF.

    CLEAR wa_marc.

  ENDLOOP.

*&---------------------------------------------------------------------*

*&      Form FRM_SUBROUTINE_DONE

*&---------------------------------------------------------------------*

FORM frm_subroutine_done USING g_taskname.

 

  rcv_jobs = rcv_jobs + 1.  "Receiving data

  CLEAR:it_md[].

  RECEIVE RESULTS FROMFUNCTION 'MD_STOCK_REQUIREMENTS_LIST_API'

     TABLES

       mdezx                    = it_md

     EXCEPTIONS

       material_plant_not_found = 1

       plant_not_found          = 2

       OTHERS                   = 3.

 

  functioncall1 = done.

 

  SORT lt_marc BY taskname.

  LOOP AT it_md INTO wa_md.

    READ TABLE lt_marc INTO lw_marc WITH KEY taskname = g_taskname BINARYSEARCH.

    MOVE-CORRESPONDING wa_md TO wa_output.

    wa_output-matnr = lw_marc-matnr.

    wa_output-werks = lw_marc-werks.

    APPEND wa_output TO it_output.

 

    CLEAR:wa_output,wa_md,lw_marc.

  ENDLOOP.

ENDFORM.                    " FRM_SUBROUTINE_DONE

SAP ABAP程序优化-多线程并行处理_第3张图片

                                                                            同步调用运行时间


SAP ABAP程序优化-多线程并行处理_第4张图片


异步调用运行时间


SE30中截取的两张运行时间图,

同步用时429s = 83sABAP程序使用时间 + 346s数据访问消耗时间;

异步用时75s = 74sABAP 程序使用时间 + <1s的数据库访问消耗时间。

本服务器Max.requests in queue = 5.  运行时间429 / 75 = 5.7,即提升了5倍多的执行效率。


同步调用完整程序:

福大

Description: 同步调用函数获取MRP明细列表DEMO


*&---------------------------------------------------------------------*
*& 程序名称:同步调用函数获取MRP明细列表DEMO
*& 程 序 名:ZDEMO_MXQ_TB
*& 开发日期:2013-05-15
*& 创 建 者:汉得
*& 申 请 者:
*&---------------------------------------------------------------------*
*& 摘要说明
*&--------*
*& 从物料工厂表MARC中获取一定的行项目,然后通过调用函数获取物料工厂对应的
*& MRP清单,将物料工厂与获取的对应清单整合输出
*&---------------------------------------------------------------------*
*& 变更记录
*&    日期          修改者           传输请求号           修改内容及原因
*&---------------  ----------  --------------------  ------------------*
*
*&---------------------------------------------------------------------*


REPORT  ZDEMO_MXQ_TB.

*----------------------------------------------------------------------*
*       Type-pools                                                     *
*----------------------------------------------------------------------*
TYPE-POOLS: slis.

*----------------------------------------------------------------------*
*       Table                                                    *
*----------------------------------------------------------------------*
TABLES:marc.

*----------------------------------------------------------------------*
*       Internal Tables and Work Areas
*----------------------------------------------------------------------*

DATA:BEGIN OF wa_marc,
  matnr TYPE marc-matnr, "物料号
  werks TYPE marc-werks, "工厂
  END OF wa_marc.

DATA:it_marc LIKE TABLE OF wa_marc.

"函数调用参数
DATA:it_md TYPE STANDARD TABLE OF mdez,
     wa_md LIKE LINE OF it_md.


DATA:BEGIN OF wa_output.
        INCLUDE STRUCTURE mdez.
DATA:matnr TYPE marc-matnr. "物料号
DATA:werks TYPE marc-werks. "工厂
DATA:END OF wa_output.

DATA:it_output LIKE TABLE OF wa_output.

*----------------------------------------------------------------------*
*       Variables
*----------------------------------------------------------------------*



*----------------------------------------------------------------------*
*       ALV层级关系定义
*----------------------------------------------------------------------*
DATA: it_fieldcat TYPE slis_t_fieldcat_alv,
      wa_layout   TYPE slis_layout_alv.
DATA: wa_fieldcat TYPE slis_fieldcat_alv.
DATA gv_grid TYPE REF TO cl_gui_alv_grid.

DATA: git_events    TYPE slis_t_event,        "ALV 事件
      git_listheader  TYPE slis_t_listheader. "ALV 表头

DATA wa_header TYPE slis_listheader.


*&---------------------------------------------------------------------*
*&      Define marco
*&---------------------------------------------------------------------*
DEFINE  macro_fill_fcat.

  clear wa_fieldcat.

  &1 = &1 + 1.
  wa_fieldcat-col_pos       = &1.
  wa_fieldcat-fieldname     = &2.
  wa_fieldcat-seltext_l     = &3.
  wa_fieldcat-seltext_m     = &3.
  wa_fieldcat-seltext_s     = &3.

  append wa_fieldcat to it_fieldcat.

END-OF-DEFINITION.


*----------------------------------------------------------------------*
*       SELECTION-SCREEN
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK blk1 WITH FRAME TITLE text-001.
*PARAMETERS:p_wp TYPE c .  "进程数
SELECT-OPTIONS:s_matnr FOR marc-matnr,
               s_werks FOR marc-werks.

SELECTION-SCREEN END OF BLOCK blk1.

*initialialization
INITIALIZATION.


*at selection screen
AT SELECTION-SCREEN.


*start of selection
START-OF-SELECTION.

  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
    EXPORTING
      PERCENTAGE = 10
      TEXT       = '数据获取中...'.

  PERFORM frm_get_date.

*END OF SELECTION
END-OF-SELECTION.
  PERFORM frm_init_fieldcat.
  PERFORM frm_init_layout.
  PERFORM frm_alv_output.



*&---------------------------------------------------------------------*
*&      Form  FRM_GET_DATE
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM FRM_GET_DATE .

  SELECT matnr werks
    UP TO 18000 ROWS                                           "最多获取20条数据
    INTO CORRESPONDING FIELDS OF TABLE it_marc
    FROM marc
    WHERE matnr IN s_matnr
    AND   werks IN s_werks.

  LOOP AT it_marc INTO wa_marc.

    CLEAR it_md.
    CALL FUNCTION 'MD_STOCK_REQUIREMENTS_LIST_API'
      EXPORTING
        MATNR                    = wa_marc-matnr
        WERKS                    = wa_marc-werks
      TABLES
        MDEZX                    = it_md
      EXCEPTIONS
        MATERIAL_PLANT_NOT_FOUND = 1
        PLANT_NOT_FOUND          = 2
        OTHERS                   = 3.

    LOOP AT it_md INTO wa_md.
      MOVE-CORRESPONDING wa_md TO wa_output.
      wa_output-matnr = wa_marc-matnr.
      wa_output-werks = wa_marc-werks.
      APPEND wa_output TO it_output.
      CLEAR:wa_output,wa_md.
    ENDLOOP.

    CLEAR wa_marc.

  ENDLOOP.


ENDFORM.                    " FRM_GET_DATE


*&---------------------------------------------------------------------*
*&      Form  FRM_INIT_FIELDCAT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_init_fieldcat.

  DATA: l_colpos TYPE lvc_s_fcat-col_pos VALUE 0.

  macro_fill_fcat l_colpos 'MATNR'   '物料号'    .
  macro_fill_fcat l_colpos 'WERKS'   '工厂'      .
  macro_fill_fcat l_colpos 'DELKZ'   'MRP元素'   .
  macro_fill_fcat l_colpos 'MNG01'   '数量'      .
  macro_fill_fcat l_colpos 'DAT00'   '日期'      .

ENDFORM.                    " FRM_INIT_FIELDCAT


*&---------------------------------------------------------------------*
*&      Form  FRM_INIT_LAYOUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_init_layout .

  wa_layout-zebra             = 'X'.
  wa_layout-f2code            = '&ETA'.   "双击显示详细信息
  wa_layout-detail_popup      = 'X'.
  wa_layout-colwidth_optimize = 'X'.
*  wa_layout-box_fieldname     = 'BOX'."将BOX字段作为选择标记列

ENDFORM.                    " FRM_INIT_LAYOUT
*&---------------------------------------------------------------------*
*&      Form  FRM_ALV_OUTPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_alv_output .
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      i_callback_program       = sy-repid
      is_layout                = wa_layout
      it_fieldcat              = it_fieldcat
      i_save                   = 'A'
*      it_events                = git_events[]
*     i_callback_pf_status_set = 'PF_STATUS_SET'
*     i_callback_user_command  = 'USER_COMMAND'
    TABLES
      t_outtab                 = it_output
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.                    " FRM_ALV_OUTPUT


*Selection texts
*----------------------------------------------------------
* S_MATNR D       .
* S_WERKS D       .

Extracted by Direct Download Enterprise version 1.3.1 - E.G

异步调用完整程序:


Code listing for: ZDEMO_MXQ_YB 
Description: 异步调用函数获取MRP明细列表DEMO


*&---------------------------------------------------------------------*
*& 程序名称:异步调用函数获取MRP明细列表DEMO
*& 程 序 名:ZDEMO_MXQ_YB
*& 开发日期:2013-05-15
*& 创 建 者:汉得
*& 申 请 者:
*&---------------------------------------------------------------------*
*& 摘要说明
*&--------*
*& 从物料工厂表MARC中获取一定的行项目,然后通过调用函数获取物料工厂对应的
*& MRP清单,将物料工厂与获取的对应清单整合输出
*&---------------------------------------------------------------------*
*& 变更记录
*&    日期          修改者           传输请求号           修改内容及原因
*&---------------  ----------  --------------------  ------------------*
*
*&---------------------------------------------------------------------*


REPORT  zdemo_mxq_yb.

*----------------------------------------------------------------------*
*       Type-pools                                                     *
*----------------------------------------------------------------------*
TYPE-POOLS: slis.

*----------------------------------------------------------------------*
*       Table                                                    *
*----------------------------------------------------------------------*
TABLES:marc.

*----------------------------------------------------------------------*
*       Internal Tables and Work Areas
*----------------------------------------------------------------------*

DATA:BEGIN OF wa_marc,
  matnr TYPE marc-matnr, "物料号
  werks TYPE marc-werks, "工厂
  taskname(10) TYPE c,   "任务名
  END OF wa_marc.

DATA:it_marc LIKE TABLE OF wa_marc.

DATA:lt_marc LIKE TABLE OF wa_marc,  "存放临时数据
     lw_marc LIKE wa_marc.

"函数调用参数
DATA:it_md TYPE STANDARD TABLE OF mdez,
     wa_md LIKE LINE OF it_md.


DATA:BEGIN OF wa_output.
        INCLUDE STRUCTURE mdez.
DATA:matnr TYPE marc-matnr. "物料号
DATA:werks TYPE marc-werks. "工厂
DATA:END OF wa_output.

DATA:it_output LIKE TABLE OF wa_output.

*----------------------------------------------------------------------*
*       Variables
*----------------------------------------------------------------------*
DATA:g_taskname(10) TYPE c,                "task name(同时运行的任务名称必须保持唯一)
     g_classname TYPE rzlli_apcl,          "Server Group Name
     g_applserver TYPE rzllitab-applserver,"RFC Serve Group
     excp_flag(1) TYPE c.     "Number of RESOURCE_FAILUREs

DATA:snd_jobs TYPE i,
     rcv_jobs TYPE i,
     functioncall1(1) TYPE c.

CONSTANTS: done(1) TYPE c VALUE 'X'.

*----------------------------------------------------------------------*
*       ALV层级关系定义
*----------------------------------------------------------------------*
DATA: it_fieldcat TYPE slis_t_fieldcat_alv,
      wa_layout   TYPE slis_layout_alv.
DATA: wa_fieldcat TYPE slis_fieldcat_alv.
DATA gv_grid TYPE REF TO cl_gui_alv_grid.

DATA: git_events    TYPE slis_t_event,        "ALV 事件
      git_listheader  TYPE slis_t_listheader. "ALV 表头

DATA wa_header TYPE slis_listheader.


*&---------------------------------------------------------------------*
*&      Define marco
*&---------------------------------------------------------------------*
DEFINE  macro_fill_fcat.

  clear wa_fieldcat.

  &1 = &1 + 1.
  wa_fieldcat-col_pos       = &1.
  wa_fieldcat-fieldname     = &2.
  wa_fieldcat-seltext_l     = &3.
  wa_fieldcat-seltext_m     = &3.
  wa_fieldcat-seltext_s     = &3.

  append wa_fieldcat to it_fieldcat.

END-OF-DEFINITION.


*----------------------------------------------------------------------*
*       SELECTION-SCREEN
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK blk1 WITH FRAME TITLE text-001.
*PARAMETERS:p_wp TYPE c .  "进程数
SELECT-OPTIONS:s_matnr FOR marc-matnr,
               s_werks FOR marc-werks.

PARAMETERS:p_wp TYPE c .  "并发进程数(根据RZ12中的最大请求队列数设置)

SELECTION-SCREEN END OF BLOCK blk1.

*initialialization
INITIALIZATION.
  p_wp = 5.

*at selection screen
AT SELECTION-SCREEN.

  "锁定程序
  CALL FUNCTION 'ENQUEUE_EZZSOPR0032'
    EXPORTING
      mode_trdir     = 'E'
      name           = 'ZSOPR0032'
      x_name         = ' '
      _scope         = '2'
      _wait          = ' '
      _collect       = ' '
    EXCEPTIONS
      foreign_lock   = 1
      system_failure = 2
      OTHERS         = 3.

  IF sy-subrc <> 0.
* Implement suitable error handling here
    MESSAGE '对象已被锁定,请稍后执行' TYPE 'E'.
  ELSE.
    "锁定成功
  ENDIF.

*start of selection
START-OF-SELECTION.

  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
    EXPORTING
      percentage = 10
      text       = '数据获取中...'.

  PERFORM frm_get_date.

*END OF SELECTION
END-OF-SELECTION.

  "解除程序的锁定
  CALL FUNCTION 'DEQUEUE_EZZSOPR0032'
    EXPORTING
      mode_trdir = 'E'
      name       = 'ZSOPR0032'
      x_name     = ' '
      _scope     = '3'
      _synchron  = ' '
      _collect   = ' '.

  PERFORM frm_init_fieldcat.
  PERFORM frm_init_layout.
  PERFORM frm_alv_output.



*&---------------------------------------------------------------------*
*&      Form  FRM_GET_DATE
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_get_date .

  DATA:mess(40) TYPE c.        "并发执行出错信息

  DATA:open_task_num TYPE i.   "启动任务数量

  SELECT matnr werks
    UP TO 18000 ROWS                                        ""数据条目18000
    INTO CORRESPONDING FIELDS OF TABLE it_marc
    FROM marc
    WHERE matnr IN s_matnr
    AND   werks IN s_werks.


*  获取 RFC Serve Group name         Start--*
* 一般系统默认g_classname = 'parallel_generators',但为了通用性按照如下方法获取
  CALL 'C_SAPGPARAM'                                      "#EC CI_CCALL
    ID 'NAME'  FIELD 'rdisp/myname'
    ID 'VALUE' FIELD g_applserver.

  SELECT SINGLE classname
    FROM rzllitab
    INTO g_classname   "Server Group Name
    WHERE applserver = g_applserver
    AND grouptype = 'S'.   "S:服务器组,空:登陆组
*  获取 RFC Serve Group name         End--*

  CLEAR open_task_num.

  LOOP AT it_marc INTO wa_marc.
*   生成任务名称 = 'Task' + sy-tabix   Start--*
    WRITE sy-tabix TO g_taskname.
    CONDENSE g_taskname.
    CONCATENATE 'Task' g_taskname INTO g_taskname.
*   生成任务名称 = 'Task' + sy-tabix   End--*

    lw_marc-taskname = g_taskname.
    lw_marc-matnr = wa_marc-matnr.
    lw_marc-werks = wa_marc-werks.
    APPEND wa_marc TO lt_marc.

*   异步调用函数    Start--*
    CALL FUNCTION 'MD_STOCK_REQUIREMENTS_LIST_API' STARTING NEW TASK g_taskname
        DESTINATION IN GROUP g_classname
        PERFORMING frm_subroutine_done ON END OF TASK "子程序
*      只要将函数的EXPORTING参数放在此处,其他参数放到子程序中
        EXPORTING
          matnr                 = wa_marc-matnr
          werks                 = wa_marc-werks

*       系统标准报错信息
        EXCEPTIONS
          communication_failure = 1  MESSAGE mess
          system_failure        = 2  MESSAGE mess
          resource_failure      = 3.

        IF sy-subrc = 0.
          snd_jobs = snd_jobs + 1.
        ENDIF.
*   异步调用函数     End--*

    open_task_num = open_task_num + 1.   "记录启动的进程数量

    IF open_task_num = p_wp.    "p_wp = RZ12中的 Max. requests in queue

*     获取并发进程返回的结果
      WAIT UNTIL rcv_jobs >= snd_jobs.

      CLEAR:open_task_num,rcv_jobs,snd_jobs.
      FREE:lt_marc.

    ENDIF.

    CLEAR wa_marc.

  ENDLOOP.

ENDFORM.                    " FRM_GET_DATE


*&---------------------------------------------------------------------*
*&      Form  FRM_SUBROUTINE_DONE
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_subroutine_done USING g_taskname.

  rcv_jobs = rcv_jobs + 1.  ""Receiving data

  CLEAR:it_md[].
  RECEIVE RESULTS FROM FUNCTION 'MD_STOCK_REQUIREMENTS_LIST_API'
     TABLES
       mdezx                    = it_md
     EXCEPTIONS
       material_plant_not_found = 1
       plant_not_found          = 2
       OTHERS                   = 3.

  functioncall1 = done.

  SORT lt_marc BY taskname.

  LOOP AT it_md INTO wa_md.
    READ TABLE lt_marc INTO lw_marc WITH KEY taskname = g_taskname BINARY SEARCH.
    MOVE-CORRESPONDING wa_md TO wa_output.
    wa_output-matnr = lw_marc-matnr.
    wa_output-werks = lw_marc-werks.
    APPEND wa_output TO it_output.

    CLEAR:wa_output,wa_md,lw_marc.
  ENDLOOP.


ENDFORM.                    " FRM_SUBROUTINE_DONE



*&---------------------------------------------------------------------*
*&      Form  FRM_INIT_FIELDCAT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_init_fieldcat.

  DATA: l_colpos TYPE lvc_s_fcat-col_pos VALUE 0.

  macro_fill_fcat l_colpos 'MATNR'   '物料号'    .
  macro_fill_fcat l_colpos 'WERKS'   '工厂'      .
  macro_fill_fcat l_colpos 'DELKZ'   'MRP元素'   .
  macro_fill_fcat l_colpos 'MNG01'   '数量'      .
  macro_fill_fcat l_colpos 'DAT00'   '日期'      .

ENDFORM.                    " FRM_INIT_FIELDCAT


*&---------------------------------------------------------------------*
*&      Form  FRM_INIT_LAYOUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_init_layout .

  wa_layout-zebra             = 'X'.
  wa_layout-f2code            = '&ETA'.   "双击显示详细信息
  wa_layout-detail_popup      = 'X'.
  wa_layout-colwidth_optimize = 'X'.
*  wa_layout-box_fieldname     = 'BOX'."将BOX字段作为选择标记列

ENDFORM.                    " FRM_INIT_LAYOUT
*&---------------------------------------------------------------------*
*&      Form  FRM_ALV_OUTPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM frm_alv_output .
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      i_callback_program       = sy-repid
      is_layout                = wa_layout
      it_fieldcat              = it_fieldcat
      i_save                   = 'A'
*     it_events                = git_events[]
*     i_callback_pf_status_set = 'PF_STATUS_SET'
*     i_callback_user_command  = 'USER_COMMAND'
    TABLES
      t_outtab                 = it_output
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.                    " FRM_ALV_OUTPUT


*Selection texts
*----------------------------------------------------------
* P_WP         并发进程数
* S_MATNR D       .
* S_WERKS D       .


*Messages
*----------------------------------------------------------
*
* Message class: Hard coded
*   对象已被锁定,请稍后执行


你可能感兴趣的:(SAP,ABAP)