abap 多线程

参考http://blog.csdn.net/zhongguomao/article/details/8963815

参考程序 ZFC_MM030C

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

同步/异步调用函数语法

同步调用:CALL FUNCTION ‘AAA‘ ;

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

异步调用:CALL FUNCTION ‘AAA‘ STARTING NEWTASK <taskname> "任务名称

DESTINATION IN GROUP <RFC Serve Group>

PERFORMING <subroutine>ON END OF TASK。"子程序

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

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

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

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

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

问题1分析:从

MD01中运行MRP我们可以知道,系统为了避免相同程序并发执行,导致后台任务冲突, MD01在

并行模式下是不允许被两个用户同时执行的。如下图

解决方法:通过在程序中利用

锁对象来达到程序相同时间段只被同一用户占用的目的。

问题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的水平可以保证获取结果的完整性。如下图所示

问题3分析:一般系统直接指定<RFC Serve Group> =‘ 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

时间: 2024-08-30 17:28:44

abap 多线程的相关文章

ABAP开发顾问必备:SAP ABAP开发技术总结

声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4260224.html 该文档是根据我过去多年学习文档与工作文档总结而成,项目开发过程中我都会参考此文档,主要ABAP很多细节上的东西不可能你记得很牢固,或者你记得一时,但过不了几天做别的项目就会

[SAP ABAP开发技术总结]BAPI调用

目录导航 声明:原创作品,转载时请注明文章来自SAP师太博客,并以超链接形式标明文章原始出处,否则将追究法律责任!原文出自: 18.3.2.5.           调用BAPI 199 18.3.2.5.1.       BAPI事务处理... 200 18.3.2.5.2.       外部系统(Java)调用BAPI函数... 201 18.3.2.5.2.1.    直连.连接池... 201 18.3.2.5.2.2.    访问结构... 202 18.3.2.5.2.3.    访

ABAP/4 技术总结 V3.0

SAP --ABAP/4 技术总结 V3.0 2014-10-14 --江正军 1.      基础... 1 1.1. 基本数据类型... 1 1.1.1.        P类型(压缩型)数据... 1 1.2.           TYPE.LIKE. 2 1.3.           DESCRIBE. 3 1.4.           字符串表达式... 3 1.5.           Data element.Domain. 4 1.6.           词典预定义类型与ABAP

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Spring多线程

Spring是通过TaskExecutor任务执行器来实现多线程和并发编程的.使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor.而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步的支持,并通过在实际执行的Bean的方法中使用@Async注解来声明其是一个异步任务. 实例代码: (1)配置类 package com.lwh.highlight_spring4.ch3.taskexecutor; /**

python进阶学习(一)--多线程编程

1. 多线程 概念:简单地说操作系统可以同时执行多个不用程序.例如:一边用浏览器上网,一边在听音乐,一边在用笔记软件记笔记. 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务"一起"执行(实际上总有一些任务不在执行,因为切换任务的熟度相当快,看上去一起执行而已) 并行:指的是任务数小于等于CPU核数,即任务真的是一起执行的. 2. 线程 概念:线程是进程的一个实体,是CPU调度和分派的基本单位. threading--单线程执行: 1 import ti

多线程的实现及其安全问题

一.进程和线程概述 1.进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动,简单来说开启一个程序就开启了一个进程: 如果开启多个进程,它们之间是由于CPU的时间片在相互的切换: 2.线程:开启一个进程的一个任务,对于多线程:每一个线程都在争夺CPU的执行权(CPU的执行权具有随机性): 如果一个程序的执行路径有多条,那么该线程是多线程;反之,就单线程线程:线程是依赖于进程存在的! 3.Jvm是多线程 -- 至少开启了两条线程 main方法 主线程 gc() 垃圾回收线程 二.多线程

多线程和多进程的区别与联系

1.单进程单线程:一个人在一个桌子上吃菜.2.单进程多线程:多个人在同一个桌子上一起吃菜.3.多进程单线程:多个人每个人在自己的桌子上吃菜. 多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了...此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢. 1.对于 Windows 系统来说,[开桌子]的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜.因此 Windows 多线程学习重点

Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?

最近正在学习Python中的异步编程,看了一些博客后做了一些小测验:对比asyncio+aiohttp的爬虫和asyncio+aiohttp+concurrent.futures(线程池/进程池)在效率中的差异,注释:在爬虫中我几乎没有使用任何计算性任务,为了探测异步的性能,全部都只是做了网络IO请求,就是说aiohttp把网页get完就程序就done了. 结果发现前者的效率比后者还要高.我询问了另外一位博主,(提供代码的博主没回我信息),他说使用concurrent.futures的话因为我全