2018年11月1日 星期四

ABAP多线程程序运行              
Author: Chaim Wang

Date: 2018/7/19

 

在ABAP中,有时因为数据量过大可能会影响用户的体验度,导出一点数据有时都会等上半个小时,为了避免这种情况,在此引用大数据的基本原理并行执行数据。减少系统运行的时间,就必须要牺牲内存或者CPU的,这里只仅仅是说明如何牺牲CPU提高程序运行速度在ABAP的执行方式。



如上图所示若将一个程序的作业量平均分成两份,则运行的时间将变成原来的一半。以此类推在扩展,数据查询时间将以成倍减少。

SUBMIT的运用
Submit在ABAP中调用其他程序的方式,(比如我们现在正在运行A程序,但是中间需要B程序运行并给我们返回数据,一般的方式我们都会直接复制B程序到A程序然后在执行)。其实submit可以很容易的传入输入参数返回输出参数在内存。关于使用方法可以参考网络或一下代码

FIELD-SYMBOLS: <Itab> TYPE data.
FIELD-SYMBOLS:<lt_data>  TYPE ANY TABLE,
              <lt_data_line>  TYPE ANY TABLE.
DATA:         lr_data               TYPE REF TO data,
              lr_data_line TYPE REF TO data.
DATA:         lr_data_descr          TYPE REF TO cl_abap_datadescr,
              lr_data_descr_line TYPE REF TO cl_abap_datadescr.
DATA:FLAG TYPE C VALUE ''.

DATA: lt_selscreen LIKE rsparams OCCURS 0.
DATA: wa_selscreen LIKE LINE OF lt_selscreen.

CLEAR:flag. "flag初始化
         cl_salv_bs_runtime_info=>set(
          EXPORTING display  = abap_false
                        metadata = abap_false
                        data     = abap_true ).
*         Submit standard program with selection table
       SUBMIT ZPPR0008 WITH SELECTION-TABLE lt_selscreen "
                          WITH p_werks = WERK_TAB-WERKSA
          AND RETURN.
        TRY."因MB51中ALV输出有header,list 所以要有2个参数
            cl_salv_bs_runtime_info=>get_data_ref(
                 IMPORTING r_data_descr      = lr_data_descr ).
                        "   r_data_line_descr = lr_data_descr_line
            IF lr_data_descr IS NOT INITIAL .
              CREATE DATA lr_data TYPE HANDLE lr_data_descr.
         "   CREATE DATA lr_data_line TYPE HANDLE lr_data_descr_line.
            ASSIGN lr_data->* TO <lt_data>.
         "   ASSIGN lr_data_line->* TO <lt_data_line>.
            cl_salv_bs_runtime_info=>get_data(
              IMPORTING
                t_data      =      <lt_data>
           "     t_data_line      =      <lt_data_line>
                   ).
            ELSE.
             "  MESSAGE '讯息:没有符合您设定的范围数据!!' TYPE 'E'.
                flag = 'X'.
            ENDIF.
          CATCH cx_salv_bs_sc_runtime_info.
          "  MESSAGE `Unable to retrieve ALV data` TYPE 'E'.
            flag = 'X'.
        ENDTRY.
        cl_salv_bs_runtime_info=>clear_all( ).
      IF flag = ''.
        LOOP AT <lt_data> ASSIGNING <Itab>.
              MOVE-CORRESPONDING <Itab> to IT_ITAB.
              APPEND IT_ITAB.
              CLEAR IT_ITAB.
        ENDLOOP.
      ENDIF.

FORM SHUJU TABLES Tab  USING A.
FIELD-SYMBOLS: <Itab1> TYPE data.
LOOP AT Tab ASSIGNING <Itab1>.
  MOVE-CORRESPONDING <Itab1> to wa_selscreen.
  wa_selscreen-selname = A.
  wa_selscreen-kind = 'S'.
APPEND wa_selscreen TO lt_selscreen.
CLEAR: wa_selscreen.
ENDLOOP.
ENDFORM.

以上是SUBMIT的处理方法,但是不足的是这个也是串行运行程序,程序运行在此处时会等待返回结果后才继续运行下去。

后台运行
其实submit可以使用后台运行,但是数据不能通过内存传输过来,运行完毕后就丢失了,所以这是我们要关注的解决的主要问题点,如果我们想想在ABAP中启动这个后台运行程序,将结果的数据在传入我们此时正在运行的程序,那么程序可以按倍数的降低运行时间。

DATA: JOBCOUNT LIKE TBTCJOB-JOBCOUNT,
      HOST LIKE MSXXLIST-HOST.
DATA: BEGIN OF STARTTIME.
        INCLUDE STRUCTURE TBTCSTRT.
DATA: END OF STARTTIME.
DATA: STARTTIMEIMMEDIATE LIKE BTCH0000-CHAR1 VALUE 'X'.
DATA: actual_status LIKE TBTCJOB-STATUS .
DATA e_return TYPE INT4.
DATA e_message TYPE CHAR40.
DATA joblogtbl LIKE RANGE OF TBTC5 WITH HEADER LINE.
DATA: JOBNAME LIKE TBTCJOB-JOBNAME.

“开始启动后台运行的方式。

CONCATENATE 'ZM08' SY-DATUM SY-UZEIT SY-UNAME INTO JOBNAME.
PERFORM JOB_OPEN CHANGING JOBNAME JOBCOUNT.
SUBMIT Z_YOUHUA_ZM08_2  WITH SELECTION-TABLE lt_selscreen
                        WITH JOBNAME  =  JOBNAME
AND RETURN
                        USER SY-UNAME
                        VIA JOB JOBNAME
                        NUMBER JOBCOUNT.
IF SY-SUBRC > 0.
     EXIT.
ENDIF.
PERFORM JOB_CLOSE USING JOBNAME JOBCOUNT.

放入A程序运行的程序

A程序运行结束后或者需要B程序的返回数据时

PERFORM JOB_CHECKSTATE USING jobname jobcount.

 

FORM JOB_OPEN CHANGING JOBNAME JOBCOUNT.
  CALL FUNCTION 'JOB_OPEN'
  EXPORTING
    DELANFREP        = ' '
    JOBGROUP         = ' '
    JOBNAME          = JOBNAME
    SDLSTRTDT        = SY-DATUM
    SDLSTRTTM        = SY-UZEIT
  IMPORTING
    JOBCOUNT         = JOBCOUNT
  EXCEPTIONS
    CANT_CREATE_JOB  = 01
    INVALID_JOB_DATA = 02
    JOBNAME_MISSING  = 03.

IF SY-SUBRC NE 0.
   EXIT.
ENDIF.
ENDFORM.

FORM JOB_CLOSE USING JOBNAME JOBCOUNT.
CALL FUNCTION 'JOB_CLOSE'
  EXPORTING
    EVENT_ID             = STARTTIME-EVENTID
    EVENT_PARAM          = STARTTIME-EVENTPARM
    EVENT_PERIODIC       = STARTTIME-PERIODIC
    JOBCOUNT             = JOBCOUNT
    JOBNAME              = JOBNAME
*    LASTSTRTDT           = STARTTIME-LASTSTRTDT
*    LASTSTRTTM           = STARTTIME-LASTSTRTTM
    PRDDAYS              = 0                    "周期执行
    PRDHOURS             = 0
    PRDMINS              = 0
    PRDMONTHS            = 0
    PRDWEEKS             = 0
*    SDLSTRTDT            = STARTTIME-SDLSTRTDT
*    SDLSTRTTM            = STARTTIME-SDLSTRTTM  "执行最后期限
    STRTIMMED            = STARTTIMEIMMEDIATE    "立刻执行
    TARGETSYSTEM         = HOST
  EXCEPTIONS
    CANT_START_IMMEDIATE = 01
    INVALID_STARTDATE    = 02
    JOBNAME_MISSING      = 03
    JOB_CLOSE_FAILED     = 04
    JOB_NOSTEPS          = 05
    JOB_NOTEX            = 06
    LOCK_FAILED          = 07
    OTHERS               = 99.

IF SY-SUBRC EQ 0.
  "error processing
ENDIF.
ENDFORM.

检测后台运行状态。
FORM JOB_CHECKSTATE USING jobname jobcount.
           CALL FUNCTION 'BP_JOB_CHECKSTATE'
            EXPORTING
              dialog                       = 'N'
              jobcount                     = jobcount
              jobname                      = jobname
            IMPORTING
              actual_status                = actual_status
            EXCEPTIONS
              checking_of_job_has_failed   = 1
              correcting_job_status_failed = 2
              invalid_dialog_type          = 3
              job_does_not_exist           = 4
              no_check_privilege_given     = 5
              ready_switch_too_dangerous   = 6
              OTHERS                       = 7.
          IF sy-subrc <> 0.
            e_return = 8.  "JOBSTATUS取得失敗
            e_message = text-008.
            RETURN.
          ENDIF.
          IF ( actual_status = 'F' )
            OR ( actual_status = 'A' ).
            RETURN.
          ENDIF.
     DO 7200 TIMES.
          WAIT UP TO 2 SECONDS.
          CALL FUNCTION 'BP_JOB_CHECKSTATE'
            EXPORTING
              dialog                       = 'N'
              jobcount                     = jobcount
              jobname                      = jobname
            IMPORTING
              actual_status                = actual_status
            EXCEPTIONS
              checking_of_job_has_failed   = 1
              correcting_job_status_failed = 2
              invalid_dialog_type          = 3
              job_does_not_exist           = 4
              no_check_privilege_given     = 5
              ready_switch_too_dangerous   = 6
              OTHERS                       = 7.
          IF sy-subrc <> 0.
            e_return = 8.  "JOBSTATUS取得失敗
            e_message = text-008.
            EXIT.
          ENDIF.
          IF ( actual_status = 'F' )
            OR ( actual_status = 'A' ).
            EXIT.
          ENDIF.
    ENDDO.
 ENDFORM.

 

3、为了避免相同程序重复运行产生的后台任务冲突,我们可以将作业名取名为用户加当前日期时间,用户不可能在同一时间开启两个相同任务运行。就算两个窗口,点击执行也有时间差,所以此问题就可以很好的避免了。

4、程序的后台运行我们已经启动了,现在关键是如何获取B程序运行的数据。

其实这里是将B运行的数据存入数据表里,再在A程序的数据表里数据查找出来,并删除数据表。建立数据表要注意一下条件。

(1)、防止多个程序的运行,数据表传入数据,或写入数据的混乱。

(2)、当有意外情况数据表里的数据未能删除,列入程序运行一般退出了。

(3)、当一个程序有多个数据表传输数据,可以用全用一个表来满足数据的传输。

所以首先我们要以作业名字为关键字。这样可以解决多个应用程序运行互不干扰,在以一个程序的标识作为关键字以防止多个表的数据传输在一个表里互不干扰,最后在一个序号作为关键字,以表示每个表数据记录的真实性。为了防止第二中情况的发生可以在数据表里加入日期,当数据表在新的一天运行的时候发现数据表里有数据,可以先进行删除不是这一天和上一天的数据。此可避免异常产生的数据的永久存放数据表。



图3 关键字数据表
--------------------- 
作者:WangChaim 
来源:CSDN 
原文:https://blog.csdn.net/Charmean/article/details/81114072 
版权声明:本文为博主原创文章,转载请附上博文链接!

沒有留言:

張貼留言