多线程

作者: abapCiCi | 来源:发表于2021-05-13 10:55 被阅读0次

    锁模式

    模式E:当更改数据的时候设置为此模式。
    模式S:本身不需要更改数据,但是希望显示的数据不被别人更改。
    模式X:和E类似,但是不允许累加,完全独占。
    

    多线程

    并行RFC(负载均衡)

    注意事项

    并行RFC调用实际上是异步RFC调用的应用之一
    异步RFC调用只适用于多个SAP ABAP系统间的并行处理,不支持SAP系统和其他系统之间
    
    独立的LUW:并行处理不适合需顺序进行的数据处理,并行的数据处理任务必须逻辑上独立于其他任务,各个数据处理过程不能具有依赖关系
    
    被调用的功能模块程序中不能再包含使用目标BACK的远程功能调用(即不能再进行回调)
    
    调用程序不能在异步调用之后生成新的内部会话,即不能在CALL FUNCTION STARTING NEW TASK语句后使用SUBMIT或CALL TRANSACTION语句
    
    不能通过CALL FUNCTION STARTING NEW TASK DESTINATION IN GROUP语句启动外部程序
    

    异步实例

    TYPES: BEGIN OF task_type,
      name TYPE string,
      dest TYPE string,
      END OF task_type.
    
    DATA:snd_jobs TYPE i,
          rcv_jobs TYPE i,
          exc_flag TYPE i,
          info TYPE rfcsi,
          mess(80),
          indx(4),
          name(8),
          task_list TYPE STANDARD TABLE OF task_type,
          task_wa TYPE task_type.
    
    DO 9 TIMES.
      indx = sy-index.
      CONCATENATE 'Task' indx INTO name.
      CALL FUNCTION 'RFC_SYSTEM_INFO'
        STARTING NEW TASK name
        DESTINATION IN GROUP DEFAULT
        PERFORMING rfc_info ON END OF TASK
        EXCEPTIONS
          system_failure        = 1  MESSAGE mess
          communication_failure = 2  MESSAGE mess
          resource_failure      = 3  .
    
      CASE  sy-subrc.
        WHEN 1 OR 2.
          MESSAGE mess TYPE 'I'.
        WHEN 3.
          MESSAGE 'Resource failure ' TYPE 'I'.
      ENDCASE.
    ENDDO.
    
    WAIT UNTIL rcv_jobs = 9 UP TO 10 SECONDS.
    LOOP AT task_list INTO task_wa.
      WRITE: / task_wa-name,task_wa-dest.
    ENDLOOP.
    
    FORM rfc_info USING name.
      task_wa-name = name.
      rcv_jobs = rcv_jobs + 1.
      RECEIVE RESULTS FROM FUNCTION 'RFC_SYSTEM_INFO'
        IMPORTING
          rfcsi_export = info
          EXCEPTIONS
            system_failure = 1 MESSAGE mess
            communication_failure = 2 MESSAGE mess.
      IF sy-subrc = 0.
        task_wa-dest = info-rfcdest.
      ELSE.
        task_wa-dest = mess.
      ENDIF.
      APPEND task_wa TO task_list.
    ENDFORM.
    

    上面的程序有问题就是当发生RESOURCE_FAILURE会丢失数据。
    需要使用子程序包装递归调用,递归调用前需要wait进程释放,否则程序一致循环,可能会占用太多系统内存,甚至产生system_no_menory错误代码如下。

    *&---------------------------------------------------------------------*
    *& Report ZTEST_YB_DEMO01
    *&---------------------------------------------------------------------*
    *&
    *&---------------------------------------------------------------------*
    REPORT ztest_yb_demo01.
    TYPES: BEGIN OF task_type,
             name TYPE string,
             dest TYPE string,
           END OF task_type.
    
    DATA: snd_jobs  TYPE i,
          rcv_jobs  TYPE i,
          exc_flag  TYPE i,
          ls_time   TYPE i,
          info      TYPE rfcsi,
          mess      TYPE c LENGTH 80,
          indx      TYPE c LENGTH 4,
          name      TYPE c LENGTH 8,
          task_list TYPE STANDARD TABLE OF task_type,
          task_wa   TYPE task_type.
    *GET TIME STAMP FIELD DATA(ls_stamp).
    
    
    DATA:g_taskname(10) TYPE c,                "task name(同时运行的任务名称必须保持唯一)
         g_classname    TYPE rzlli_apcl,          "Server Group Name
         g_applserver   TYPE rzllitab-applserver, "RFC Serve Group
         lv_available   TYPE i,
         lv_total       TYPE i,
         lv_job         TYPE i.
    
    
    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--*
    CALL FUNCTION 'SPBT_INITIALIZE'
      EXPORTING
        group_name                     = g_classname
      IMPORTING
        max_pbt_wps                    = lv_total
        free_pbt_wps                   = lv_available
      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.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.
    
    GET RUN TIME FIELD ls_time.
    DO 200 TIMES.
      indx = sy-index.
      CONCATENATE 'Task' indx INTO name.
      PERFORM frm_parallel_task USING name.
    ENDDO.
    WAIT UNTIL rcv_jobs GE snd_jobs .
    *GET TIME STAMP FIELD DATA(ls_stamp1).
    GET RUN TIME FIELD ls_time.
    ls_time = ls_time / 1000000.
    WRITE:/ `运行时间` && ls_time.
    LOOP AT task_list INTO task_wa.
      WRITE: / task_wa-name, ', Server:', task_wa-dest.
    ENDLOOP.
    
    FORM rfc_info USING name.
      task_wa-name = name.
      rcv_jobs = rcv_jobs + 1.
      RECEIVE RESULTS FROM FUNCTION 'RFC_SYSTEM_INFO'
      IMPORTING
        rfcsi_export = info
      EXCEPTIONS
        system_failure        = 1 MESSAGE mess
        communication_failure = 2 MESSAGE mess.
    
      IF sy-subrc = 0.
        task_wa-dest = info-rfcdest.
      ELSE.
        task_wa-dest = mess.
      ENDIF.
      APPEND task_wa TO task_list.
      CLEAR  task_wa.
    ENDFORM.
    *&---------------------------------------------------------------------*
    *& Form FRM_PARALLEL_TASK
    *&---------------------------------------------------------------------*
    *& text
    *&---------------------------------------------------------------------*
    *      -->P_NAME  text
    *&---------------------------------------------------------------------*
    FORM frm_parallel_task  USING    p_name.
      CALL FUNCTION 'RFC_SYSTEM_INFO'
        STARTING NEW TASK name
    *    DESTINATION IN GROUP DEFAULT "g_classname  "' 390' "pRFC
        DESTINATION 'NONE'
        PERFORMING rfc_info ON END OF TASK
        EXCEPTIONS
          system_failure        = 1 MESSAGE mess
          communication_failure = 2 MESSAGE mess
          resource_failure      = 3.
    
      CASE sy-subrc.
        WHEN 0.
    *      WAIT UP TO 1 SECONDS.
          snd_jobs = snd_jobs + 1.
        WHEN 1 OR 2.
          MESSAGE mess TYPE 'I'.
        WHEN 3.
          WAIT UP TO '0.1' SECONDS.
          PERFORM frm_parallel_task USING p_name.
        WHEN OTHERS.
          MESSAGE 'Other error' TYPE 'I'.
          RETURN.
      ENDCASE.
    ENDFORM.
    

    来自引用

    1、DIALOG程序获得用户要更新的数据,并把它写到一个特殊的LOG TABLE,表内的条目属于同一个请求类型,包含了稍后将要写到数据库的数据。一个DIALOG程序可以写多条数据到LOG TABLE。写进LOG TABLE里的条目属于同一个LUW,意思就是它们要么都被执行,要么都不被执行。
    2、DIALOG程序关闭LUW(将LOG TABLE的条目打包),并通知系统基本程序有一个包的数据需要更新。
    3、系统基本程序从LOG TABLE读取这个LUW的需要更新的数据,并把这些数据提供给系统更新程序。
    4、系统更新程序接受传输给它的数据,并更新数据库。
    5、如果更新程序运行成功,系统基本程序删除这个LUW在LOG TABLE的所有数据;如果失败,保持LOG TABLE的这些数据,并标记不成功。触发更新程序的用户会收到系统发的关于这个错误的E-MAIL。可以用参数rdisp/vbmail(1发,0不发)来控制错误时是否发E-MAIL和rdisp/vb_mail_user_list($ACTUSER代表创建更新数据的用户)来控制错误时发E-MAIL给谁。可以用事务SM13来监控更新请求。

    在DIALOG程序中,通过一个特别的FM,使用IN UPDATE TASK。如:
    CALL FUNCTON 'F1' IN UPDATE TASK
    EXPORTING
    P1 = A
    P2 = B.
    使用这样写法的FM不会立即执行,而是写进LOG TABLE,作为一个执行请求,一个SAP LUW下的更新请求存储在同一个UPDATE KEY下。对一个SAP LUW来说UPDATE KEY是一个唯一的世界范围的识别码,意思就是一个SAP LUW的UPDATE KEY是唯一的,不会和另外的SAP LUW的UPDATE KEY重复。
    只有当程序执行到COMMIT WORK的时候,才会为这些请求创建一个抬头条目LOG HEADER,表示以上这些同样UPDATE KEY的属于同一个包,然后系统关闭这个LUW。当LOG HEADER创建以后,系统通知DISPATCHER有一个更新包已经准备好可以处理了。

    相关文章

      网友评论

          本文标题:多线程

          本文链接:https://www.haomeiwen.com/subject/ykmtjltx.html