一般在遇到数据量比较大,且数据之间相对比较独立的时候可以使用多线程
进行,使用的具体步骤和注意点如下:
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、对需要操作内表循环调用
IF jobs = 0.
"等待反馈
WAIT UNTIL snd_jobs - rcv_jobs < do_i.
CONTINUE.
ENDIF.
4、多个 FM 进行调用
同时这里有两个函数可供参考:SPBT_GET_PP_DESTINATION:获取当前在并行处理的服务,
SPBT_DO_NOT_USE_SERVER,可避免在这个服务上开并行(已有并行处理;不可用的的;
或在不适合于并行处理的)
5、FM 执行完后数据返回
Note:对于线程并发,内表数据过大的时候,建议把数据在单个线程执行时插入到数据表中,
注意流水号的给出(如流水号给出前 10,后 10 位单线程里面自己进行累加)
,以免一直锁
定;另外插入数据表示不宜太过频繁插入,累计数据达 50 万或者单线程执行结束,插入数
据表尽量采用:INSERT,MODIFY 会出现锁的情况。
附录:源代码
**********************主程序
*&-------------------------------------------------------------------
--*
*& Report ZDEMO_YC
*&
*&-------------------------------------------------------------------
--*
*&
*&
*&-------------------------------------------------------------------
--*
*结构
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.
GET TIME.
WRITE: '多线程开始 ', sy-datum, sy-uzeit.
*正常情况下的无资源
IF snd_jobs - rcv_jobs = jobs.
WAIT UNTIL snd_jobs - rcv_jobs < jobs .
CONTINUE.
ENDIF.
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.
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.
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.