Anda di halaman 1dari 10

Abap 多线程整理

一般在遇到数据量比较大,且数据之间相对比较独立的时候可以使用多线程
进行,使用的具体步骤和注意点如下:

1、形成多线程需要处理的内表

本次使用 it_resb,对于内表中的数据进行一条一条的处理,当然如果你的执行函数支持
内表处理,那么可以对 it_resb 分块分到一个的小内表中,然后分别将小内表赋值给线程。

Note: 如果将内表赋值给线程成功,线程启动,那么清空小内表,并重新赋值;如果线程启
动失败,那么不能清空小内表,下次循环时判断小内表是否有值从而确定是否重新赋值。即
在失败后需要将值写会。

2、获取系统的可用资源数量

在获取资源数量之前,可以先定义一个服务组,从而标识所开线程均属于该服务组。可
以控制哪些服务器可用于并行处理,可以避免并行作业将所有系统资源消耗完,影响其他事
务的性能,同时组内可以优化资源共享;server group 可以用 RZ12 进行维护,参数直接复
制即可,不用修改,
然后调用 SPBT_INITIALIZE 进行初始化(group 可以不用)获取资源数量:
CALL FUNCTION 'SPBT_INITIALIZE'
EXPORTING
group_name = group
IMPORTING
max_pbt_wps = wp_total
free_pbt_wps = wp_available
EXCEPTIONS
invalid_group_name = 1
internal_error = 2 "SAP System error SM21 查看
pbt_env_already_initialized = 3 "函数已经调用
currently_no_resources_avail = 4 "No resources
no_pbt_resources_found = 5 "No servers in the group
cant_init_different_pbt_groups = 6"initialize a different
OTHERS = 7.
如果此时获得资源成功,wp_available 有值,那么可以选择 3/4 * wp_available 或者其他比
例作为本次拟使用资源数。如果此次获得资源数量过少或者没有获取到,可以选择等待,等
待时,如果要重新获取资源,需要调用另外一个函数:
CALL FUNCTION 'SPBT_GET_CURR_RESOURCE_INFO'
IMPORTING
max_pbt_wps = wp_total
free_pbt_wps = wp_available
EXCEPTIONS
internal_error = 1
pbt_env_not_initialized_yet = 2
OTHERS = 3.
Note : 这 两 个 函 数 必 须 配 合 使 用 , 不 能 只 使 用 其 中 任 何 一 个 , 因 为 多 次 调 用
SPBT_INITIALIZE 会出现无结果,仅调用 SPBT_GET_CURR_RESOURCE_INFO 出现无结果。
调用方式,首先调一次 SPBT_INITIALIZE,如果资源数量过少或者没有获取到,循环调用
SPBT_GET_CURR_RESOURCE_INFO,直到获取到资源。

3、对需要操作内表循环调用

建议使用 while 循环,在 while 里面分割内表,将需要本次处理的数据从主内表取出,


但不删除主内表,而是记录下主键或者索引,以待成功是删除。一般做多线程并发的时候,
喜欢在所有线程执行完后才 获取反馈数据,本处不推荐这种做法,因为这样做对于调试或
者实时跟踪不方便,建议在循环中不断去获取 以执行完线程的反馈数据;
Note:线程与主程序交换数据有两种方式:
 线程执行完后,主动通知主程序,
 主程序去检测线程是否执行完。
ABAP 中是采用第二种,因此多线程主程序有两种模式分配模式和监控模式,而
WAIT UNTIL 在执行时可以将主程序的分配模式转为监控模式。
 如果要调试一个多线程的程序,那么要把线程总数调到最大会话数一下。
WHILE it_resb IS NOT INITIAL.

IF jobs = 0.
"等待反馈
WAIT UNTIL snd_jobs - rcv_jobs < do_i.
CONTINUE.
ENDIF.

4、多个 FM 进行调用

在这里需要在 SE37 中写一个函数以进行调用,在调用这个函数时,以新作业的方式进


行调用,并定义返回函数,关键字:CALL FUNCTION <function> STARTING NEW TASK
<taskname> with the DESTINATION IN GROUP;
CALL FUNCTION 'ZDQ_PP_036_CALL001'
STARTING NEW TASK taskname
DESTINATION IN GROUP group
PERFORMING return_info_data ON END OF TASK
TABLES
tab_input = it_matnr
EXCEPTIONS
communication_failure = 1 MESSAGE msg
system_failure = 2 MESSAGE msg
resource_failure = 3.
在后面需要查看分配情况 ,通过 sy-subrc;等于 0 时,执行成功,等于 1 或者 2 时,通讯
失败或者系统错误,等于 3 表示无资源,等待

同时这里有两个函数可供参考:SPBT_GET_PP_DESTINATION:获取当前在并行处理的服务,
SPBT_DO_NOT_USE_SERVER,可避免在这个服务上开并行(已有并行处理;不可用的的;
或在不适合于并行处理的)

Note:在 while 执行完后,还应该调用一次 WAIT UNTIL rcv_jobs >= snd_jobs.,并


处理扫尾工作

5、FM 执行完后数据返回

调用前面分配时的返回 form 进行数据返回


RECEIVE RESULTS FROM FUNCTION 'ZDQ_PP_036_CALL001'
TABLES
tab_output = it_mrp
it_plnum = it_plnum_list
EXCEPTIONS
communication_failure = 1 MESSAGE msg
system_failure = 2 MESSAGE msg
resource_failure = 3.
不论出现何种异常,在此时均需要,把可用作业+1 ,接受作业+1.

Note:对于线程并发,内表数据过大的时候,建议把数据在单个线程执行时插入到数据表中,
注意流水号的给出(如流水号给出前 10,后 10 位单线程里面自己进行累加)
,以免一直锁
定;另外插入数据表示不宜太过频繁插入,累计数据达 50 万或者单线程执行结束,插入数
据表尽量采用:INSERT,MODIFY 会出现锁的情况。

附录:源代码

**********************主程序
*&-------------------------------------------------------------------
--*
*& Report ZDEMO_YC
*&
*&-------------------------------------------------------------------
--*
*&
*&
*&-------------------------------------------------------------------
--*

REPORT ZDEMO_YC MESSAGE-ID zdq01.

*结构
TYPES :
BEGIN OF ty_test,
col1 TYPE i,
col2 TYPE i,
col3 TYPE i,
END OF ty_test.
*内表
DATA :
it_test TYPE STANDARD TABLE OF ty_test,
it_exe TYPE STANDARD TABLE OF ty_test .

*工作区
DATA :
wa_test TYPE ty_test,
wa_exe TYPE ty_test.

*变量
DATA: GROUP LIKE RZLLITAB-CLASSNAME VALUE ' ',
WP_AVAILABLE TYPE I,
WP_TOTAL TYPE I,
l_init_flag TYPE c,
JOBS TYPE I VALUE 10, "Number of parallel jobs
SND_JOBS TYPE I VALUE 1, "Work packets sent for proces
sing
RCV_JOBS TYPE I VALUE 1, "Work packet replies received
TASKNAME(4) TYPE N VALUE '0001', "Task name
msg(50),
BEGIN OF TASKLIST OCCURS 10, "Task administration
TASKNAME(4) TYPE C,
RFCDEST LIKE RFCSI-RFCDEST,
RFCHOST LIKE RFCSI-RFCHOST,
END OF TASKLIST.
*获取可用资源
PERFORM frm_get_jobs_available.

*给内表赋值
PERFORM frm_putdata.

*循环调用内表进行多线程处理
PERFORM frm_handle_data.

*&-------------------------------------------------------------------
--*
*& Form FRM_GET_JOBS_AVAILABLE
*&-------------------------------------------------------------------
--*
* 获取可用资源
*--------------------------------------------------------------------
--*
FORM frm_get_jobs_available .
"第一次获取资源
jobs = 0.
IF l_init_flag IS INITIAL.
"资源查询 - 获取最多 jobs 个数
CALL FUNCTION 'SPBT_INITIALIZE'
EXPORTING
group_name = group
IMPORTING
max_pbt_wps = wp_total
free_pbt_wps = wp_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.

CASE sy-subrc.
WHEN 0.
jobs = wp_available * 9 / 10.
IF jobs = 0 AND wp_available = 1.
jobs = 1.
ENDIF.
l_init_flag = 'X'.
"按照 jobs 来进行数据拆分
WHEN 1.
* MESSAGE E836."未定义 PBT 服务器组
WHEN 2.

WHEN 3.
* MESSAGE E833."已为组初始化了 PBT 环境
WHEN 4.
* MESSAGE E837."所有服务器正忙:没有可用的资源
WHEN 5.
WHEN 6.
ENDCASE.

"刷新资源数量
ELSE.
CALL FUNCTION 'SPBT_GET_CURR_RESOURCE_INFO'
IMPORTING
max_pbt_wps = wp_total
free_pbt_wps = wp_available
EXCEPTIONS
internal_error = 1
pbt_env_not_initialized_yet = 2
OTHERS = 3.
CASE sy-subrc .
WHEN 0.
jobs = wp_available * 9 / 10.
IF jobs = 0 AND wp_available = 1.
jobs = 1.
ENDIF.
WHEN 1.
WHEN 2.
CLEAR l_init_flag.
PERFORM frm_get_jobs_available .
WHEN 3.

ENDCASE.
ENDIF.
ENDFORM. " FRM_GET_JOBS_AVAILABLE
*&-------------------------------------------------------------------
--*
*& Form FRM_PUTDATA
*&-------------------------------------------------------------------
--*
* 给内表赋值
*--------------------------------------------------------------------
--*
FORM FRM_PUTDATA .

DO 40 TIMES.
CLEAR wa_test.
wa_test-col1 = sy-tabix.
wa_test-col2 = sy-tabix ** 2.

APPEND wa_test to it_test.


ENDDO.
ENDFORM. " FRM_PUTDATA
*&-------------------------------------------------------------------
--*
*& Form FRM_HANDLE_DATA
*&-------------------------------------------------------------------
--*
* 多线程处理数据
*--------------------------------------------------------------------
--*
FORM FRM_HANDLE_DATA .

GET TIME.
WRITE: '多线程开始 ', sy-datum, sy-uzeit.

WHILE NOT it_test IS INITIAL .

*正常情况下的无资源
IF snd_jobs - rcv_jobs = jobs.
WAIT UNTIL snd_jobs - rcv_jobs < jobs .
CONTINUE.
ENDIF.

READ TABLE it_test INTO wa_exe INDEX 1.


APPEND wa_exe to it_exe.

IF NOT it_exe IS INITIAL .

wait UP TO 1 SECONDS.

"并行处理掉 AFKO
CALL FUNCTION 'ZTEST_YC'
STARTING NEW TASK taskname
DESTINATION IN GROUP group
PERFORMING return_info_data ON END OF TASK
TABLES
it_exe = it_exe
EXCEPTIONS
communication_failure = 1 MESSAGE msg
system_failure = 2 MESSAGE msg
resource_failure = 3.

CASE sy-subrc.
WHEN 0.
tasklist-taskname = taskname.
APPEND tasklist.

MESSAGE s000 WITH 'Started task: ' tasklist-taskname '第一行:


' wa_exe-col1.

taskname = taskname + 1."任务名称+1


snd_jobs = snd_jobs + 1."已发送作业
*分配成功 删除数据
DELETE it_test INDEX 1.

WHEN 1 OR 2."通讯错误 系统错误


MESSAGE s000 WITH '通讯错误或者系统失败' msg.

WHEN 3."无资源,等待
*中途资源出现问题等待
WAIT UNTIL rcv_jobs >= snd_jobs UP TO '5' SECONDS.

ENDCASE.

CLEAR wa_exe.
CLEAR it_exe.

ENDIF.
ENDWHILE.

*等待最后一批的反馈
WAIT UNTIL rcv_jobs >= snd_jobs.
GET TIME.
WRITE: / '多线程结束', sy-datum, sy-uzeit.
LOOP AT TASKLIST.
WRITE:/ 'Received task:', TASKLIST-TASKNAME COLOR 1,
30 'Destination: ', TASKLIST-RFCDEST COLOR 1.
ENDLOOP.

ENDFORM. " FRM_HANDLE_DATA


*&-------------------------------------------------------------------
--*
*& Form RETURN_INFO_DATA
*&-------------------------------------------------------------------
--*
* 接受程序
*--------------------------------------------------------------------
--*
FORM RETURN_INFO_DATA USING taskname.

RECEIVE RESULTS FROM FUNCTION 'ZTEST_YC'


TABLES
it_exe = it_exe
EXCEPTIONS
communication_failure = 1 MESSAGE msg
system_failure = 2 MESSAGE msg
resource_failure = 3.

CASE sy-subrc.
WHEN 0.
free it_exe.
WHEN 1 or 2.
MESSAGE s000 WITH '通讯错误或者系统失败' msg.
when 3.
MESSAGE s000 WITH '资源分配失败'.
WHEN OTHERS.
ENDCASE.
*不论怎么样都要 rcv_
rcv_jobs = rcv_jobs + 1.

MESSAGE s000 WITH 'Received task:' taskname.


ENDFORM. " RETURN_INFO_DATA
*******************线程函数
FUNCTION ZTEST_YC.
*"-------------------------------------------------------------------
---
*"*"本地接口:
*" TABLES
*" IT_EXE STRUCTURE ZTETS_EXE
*"-------------------------------------------------------------------
---
wait UP TO 1 SECONDS.
ENDFUNCTION.

Anda mungkin juga menyukai