Zum Inhalt springen

Parallelverarbeitung unter ABAP mit der Klasse cl_abap_parallel

Unter ABAP gibt es einige Frameworks für die Parallelverarbeitung verschiedener Schritte im System was natürlich bei intensiven Verarbeitungen immer sinnvoll ist allerdings die Systemauslastung immer noch in einem gewissen Rahmen halten sollte. Die Framworks die ich kenne verschalen meist den Funktionsbausteinaufruf + STARTING NEW TASK

Mit Embedded ABAP (Steampunk) hat SAP allerdings eine API mit der Klasse CL_ABAP_PARALLEL bereitgestellt, quasi als Standard-Funktionalität was natürlich zusätzlich den Charm hat, dass diese API gewhitelistet ist.

Allerdings funktioniert die Klasse durch Downport mittlerweile sogar schon ab Release 7.50. Sollte die Klasse fehlen gibt es auch einen Hinweis für den Downport. -> Hinweis 2791374 

Was ich allerdings nicht wirklich gefunden habe sind wirklich einfache Beispiele, wie man diese Möglichkeit der Parallelisierung einsetzt. Grundsätzlich sieht die API nicht wirklich schwer aus allerdings muss man trotz allem erstmal wissen wie man seine Anwendung drumherum aufbaut um die Parallelisierung zu nutzen. Natürlich ist die API einigermaßen dokumentiert.

Die technischen Parameter zum Ablauf der Parallelisierung kann man relativ variabel bei der Instanziierung mitgeben:

Ich habe mich mal an einigen Beispielen versucht.

Beispiel 1: Parallelverarbeitung über Instanzen

REPORT zr_test_abap_parallel_inst.
DATA(lo_parallel) = NEW cl_abap_parallel( ).

DATA(lo_test_1) = NEW zcl_test_abap_parallel_inst_1( ).
DATA(lo_test_2) = NEW zcl_test_abap_parallel_inst_2( ).

lo_parallel->run_inst(
  EXPORTING
    p_in_tab  = VALUE #( ( lo_test_1 ) ( lo_test_2 ) )
  IMPORTING
    p_out_tab = DATA(lt_out)
).

LOOP AT lt_out ASSIGNING FIELD-SYMBOL(<ls_out>).
    if <ls_out>-inst is instance of zcl_test_abap_parallel_inst_1.
    lo_test_1 = CAST #( <ls_out>-inst ).
    WRITE: 'Testdaten 1 (Uhrzeit):'.
    loop at lo_test_1->get_testdata_1( ) ASSIGNING FIELD-SYMBOL(<lv_testdata_1>).
        write:/ <lv_testdata_1>.
    endloop.
    WRITE:/ |Workprozess: { lo_test_1->get_current_workprocess( ) }|.
    endif.
    if <ls_out>-inst is instance of zcl_test_abap_parallel_inst_2.
    lo_test_2 = CAST #( <ls_out>-inst ).
    WRITE:/ 'Testdaten 2 (Uhrzeit):'.
    loop at lo_test_2->get_testdata_2( ) ASSIGNING FIELD-SYMBOL(<lv_testdata_2>).
        write:/ <lv_testdata_2>.
    endloop.
    WRITE:/ |Workprozess: { lo_test_2->get_current_workprocess( ) }|.
    endif.
ENDLOOP.
CLASS zcl_test_abap_parallel_inst_1 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    TYPES tty_testdata TYPE STANDARD TABLE OF sy-uzeit WITH DEFAULT KEY.
    INTERFACES if_abap_parallel.
    METHODS get_testdata_1 RETURNING VALUE(rt_testdata) TYPE tty_testdata.
    METHODS get_current_workprocess RETURNING VALUE(rv_current_workprocess) TYPE wpindex.
  PROTECTED SECTION.
  PRIVATE SECTION.
    DATA mt_testdata_1 TYPE TABLE OF sy-uzeit.
    DATA mv_current_workprocess TYPE wpindex.
ENDCLASS.



CLASS zcl_test_abap_parallel_inst_1 IMPLEMENTATION.

  METHOD if_abap_parallel~do.
    DO 5 TIMES.
      WAIT UP TO 5 SECONDS.
      APPEND sy-uzeit TO mt_testdata_1.
    ENDDO.

    CALL FUNCTION 'TH_GET_OWN_WP_NO'
      IMPORTING
        wp_index = mv_current_workprocess.
  ENDMETHOD.

  METHOD get_testdata_1.
    rt_testdata = mt_testdata_1.
  ENDMETHOD.

  METHOD get_current_workprocess.
    rv_current_workprocess = mv_current_workprocess.
  ENDMETHOD.

ENDCLASS.
CLASS zcl_test_abap_parallel_inst_2 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    TYPES tty_testdata TYPE STANDARD TABLE OF sy-uzeit WITH DEFAULT KEY.
    INTERFACES if_abap_parallel.
    METHODS get_testdata_2 RETURNING VALUE(rt_testdata) TYPE tty_testdata.
    METHODS get_current_workprocess RETURNING VALUE(rv_current_workprocess) TYPE wpindex.
  PROTECTED SECTION.
  PRIVATE SECTION.
    DATA mt_testdata_2 TYPE TABLE OF sy-uzeit.
    DATA mv_current_workprocess TYPE wpindex.
ENDCLASS.



CLASS zcl_test_abap_parallel_inst_2 IMPLEMENTATION.

  METHOD if_abap_parallel~do.
    DO 5 TIMES.
      WAIT UP TO 5 SECONDS.
      APPEND sy-uzeit TO mt_testdata_2.
    ENDDO.

    CALL FUNCTION 'TH_GET_OWN_WP_NO'
      IMPORTING
        wp_index = mv_current_workprocess.
  ENDMETHOD.

  METHOD get_testdata_2.
    rt_testdata = mt_testdata_2.
  ENDMETHOD.

  METHOD get_current_workprocess.
    rv_current_workprocess = mv_current_workprocess.
  ENDMETHOD.

ENDCLASS.

Das Ergebnis des Reports zeigt, dass die do-Methoden parallel ausgeführt wurden und das auch in zwei verschiedenen Workprozessen:

Beispiel 2: Parallelverarbeitung direkt über Vererbung

REPORT zr_test_abap_parallel.
DATA lt_test TYPE stringtab.
DATA lv_test_all TYPE string.
DATA lt_in_tab TYPE STANDARD TABLE OF xstring.
DATA lv_buffer TYPE xstring.
DATA lv_buffer_all TYPE xstring.
DATA lv_result TYPE string.

DATA(lo_parallel) = NEW zcl_test_abap_paralell( ).
lt_test = VALUE #( ( |Ich bin Task 1| )
                   ( |Ich bin Task 2| )
                   ( |Ich bin Task 3| )  ).
lv_test_all = 'Ich gelte für alle Tasks'.
EXPORT test_all = lv_test_all to DATA BUFFER lv_buffer_all.
LOOP AT lt_test ASSIGNING FIELD-SYMBOL(<lv_test>).
  EXPORT test = <lv_test> TO DATA BUFFER lv_buffer.
  APPEND lv_buffer TO Lt_IN_TAB.
ENDLOOP.
lo_parallel->run(
  EXPORTING
    p_in_tab  = lt_in_tab
    p_in_all  = lv_buffer_all
  IMPORTING
    p_out_tab = DATA(lt_out_tab)
).

LOOP AT Lt_OUT_TAB ASSIGNING FIELD-SYMBOL(<Lv_OUT>) WHERE result IS NOT INITIAL.
  IMPORT test = Lv_result FROM DATA BUFFER <Lv_OUT>-result.
  WRITE:/ lv_result.
ENDLOOP.
CLASS zcl_test_abap_paralell DEFINITION INHERITING FROM cl_abap_parallel
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    METHODS do REDEFINITION.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_test_abap_paralell IMPLEMENTATION.
  METHOD do.
    DATA lv_test TYPE string.
    DATA lv_test_all TYPE string.
    DATA lv_current_workprocess TYPE wpinfo-wp_index.
    IMPORT test = lv_test FROM DATA BUFFER p_in.
    IMPORT test_all = lv_test_all FROM DATA BUFFER p_in_all.

    DATA(lv_beginn) = sy-uzeit.
    WAIT UP TO 10 SECONDS.
    DATA(lv_ende) = sy-uzeit.
    CALL FUNCTION 'TH_GET_OWN_WP_NO'
      IMPORTING
        wp_index = lv_current_workprocess.
    lv_test = |{ lv_test } Workprozess: { lv_current_workprocess } Beginn: { lv_beginn TIME = ENVIRONMENT } Ende: { lv_ende TIME = ENVIRONMENT  } Alle: { lv_test_all }|.

    EXPORT test = lv_test TO DATA BUFFER p_out.
  ENDMETHOD.

ENDCLASS.

Es wurden unterschiedliche Instanzen der erbenden Klasse erzeugt, die die entsprechende Verarbeitung parallel durchführen.

Mir ist allerdings aufgefallen, dass je nach Release unterschiedliche Funktionalitäten vorhanden sind. Das Interface if_abap_parallel habe ich auf einem 7.50 er System nicht gefunden genauso wie die Möglichkeit Parameter an alle Parallelisierungsinstanzen mitzugeben (Parameter p_in_all). Daher habe ich die Beispiele jetzt auch mal nicht in GitHub hochgeladen. Ich hoffe sie helfen trotzdem etwas. 🙂

Facebooktwitterpinterestlinkedinmail
Published inABAPSAP Entwicklung

Ein Kommentar

  1. Elias Kekakos

    Hello and thanks for this valuable as I could not find another one as helpful as yours.
    But I have a problem and I need your opinion on this. I used your 1st example with 5 parallel processes but for one of them I get the following error “RFC task 5 already open.” and the line of the LS_OUT was initial. Is there any way to control it? In RZ12 there is only 1 instance, do we need a new one for parallel processes?
    Thanks in advance,
    Elias

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert