ExecutorServiceの終了に関する完了可能な将来の問題

mkovacek:

基本的なWebスクラッパーを実行しています。

Completable futureを使用して、複数のスレッドと並行してスクラップを実行したい。各ジョブは、スクラップする必要があるPageオブジェクトを取得し、作成されたURLのリストを含むPageオブジェクトを返します。

リストからの各URLは、まだスクラップに送信されていない場合、新しいジョブを開始します。すべての並列ジョブが完了したら、ロジックを続行します。

「allFutures.thenRun(()-> executorService.shutdown());」を削除すると、最初のページオブジェクトのみをスクレイピングして終了するこのコードの問題 次に、すべてのページ/ URLを収集しますが、プログラムは終了しません。

public class Demo
{
    private final Set<Page> pages = new HashSet<>();
    private final Set<Page> submittedPages = new HashSet<>();

    private final ExecutorService executorService;

    public Demo(final int numberOfThreads)
    {
        this.executorService = Executors.newFixedThreadPool(numberOfThreads);
    }

    public void start(String url) throws ExecutionException, InterruptedException
    {
        this.submitTask(new Page(url));
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[completableFutureList.size()]));
        allFutures.thenRun(() -> executorService.shutdown());

        // do something with pages
    }


    private void submitTask(final Page page)
    {
        if (!this.submittedPages.contains(page))
        {
            this.submittedPages.add(page);
            CompletableFuture<Void> cf = CompletableFuture.supplyAsync(() -> new Task(page).call(), this.executorService) //want to run this parallel in multiple threads
               .thenAccept(receivedPage -> {
                   this.savePage(receivedPage);
                   this.submitCollectedLinks(receivedPage);
               });
            completableFutureList.add(cf);

        }
    }

    private void submitCollectedLinks(final Page page){
        page.getLinks()
          .stream()
          .map(Page::new)
          .forEach(this::submitTask);
    }

    private void savePage(final Page page)
    {
        this.pages.add(page);
    }

}
ホルガー:

コードにはいくつかの問題があります。completableFutureList後で追加される先物がある可能性がある場合のスナップショットの完了時にexecutorサービスのシャットダウンをスケジュールしていますが、さらに悪いことに// do something with pages、スナップショットさえまだ完了していない時点達しています。

の宣言は示していませんがcompletableFutureList異なるスレッドから変更したpagesand がスレッドセーフではないでsubmittedPages初期化されていることを考えるHashSetリストについても気分がよくありません。しかし、とにかくリストは必要ありません。送信コードを変更して、後続のタスク構成される保留中のタスクを表すフューチャーを返す必要があります。渡された関数はthenCompose、前提条件の段階が完了したときに評価されます。つまり、これにより、関数のチェーン時に不明な先物への依存が可能になります。

HashSetsをスレッドセーフ構造に置き換えるだけでは不十分であることに注意してください他のスレッドがこれら2つの呼び出しの間に実行しないことが保証されていないため(「check-then-act」アンチパターンと呼ばcontainsれる)addbeforeのようなシーケンスを回避する必要がありaddます。justを使用できますadd。これは、すでに何もせずfalse、要素がすでに存在する場合に戻ります。適切なスレッドセーフSet実装を使用して、必要な原子性を提供します。

これらをまとめると、例えば、

public class Demo {
    private final Set<Page> pages = ConcurrentHashMap.newKeySet();
    private final Set<Page> submittedPages = ConcurrentHashMap.newKeySet();

    private final ExecutorService executorService;

    public Demo(final int numberOfThreads) {
        this.executorService = Executors.newFixedThreadPool(numberOfThreads);
    }

    public void start(String url) {
        this.submitTask(new Page(url))
            // shutdown even in the exceptional case
            .whenComplete((_void, throwable) -> executorService.shutdown())
            .join(); // wait for completion before doing something with pages

        // do something with pages
    }

    private CompletableFuture<Void> submitTask(final Page page) {
        // use a single add to avoid check-then-act anti-pattern
        if(this.submittedPages.add(page)) {
            return CompletableFuture.supplyAsync(new Task(page)::call, executorService)
                // compose with recursively encountered tasks
               .thenCompose(receivedPage -> {
                   this.savePage(receivedPage);
                   return this.submitCollectedLinks(receivedPage);
               });
        }

        // do nothing when already submitted
        return CompletableFuture.completedFuture(null);
    }

    private CompletableFuture<Void> submitCollectedLinks(final Page page) {
        return CompletableFuture.allOf(page.getLinks()
          .stream().map(Page::new).map(this::submitTask)
          .toArray(CompletableFuture<?>[]::new));
    }

    private void savePage(final Page page) {
        this.pages.add(page);
    }
}

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

約束の完了に関する問題

分類Dev

TableSorterの表示可能な行の初期数に関する問題

分類Dev

完了可能な将来の失敗における情報の伝播

分類Dev

ElementaryOS上のTexMakerでの完了に関する問題

分類Dev

'!'の使用に関する問題 将来のリリースで削除されます

分類Dev

将来の完了前に返す関数

分類Dev

<Tab>を再利用可能な関数に配置するのに問題がある

分類Dev

flatMapCompletableの後に完了可能なチェーンの問題

分類Dev

Javaの最終変数の初期化に関する問題

分類Dev

Androidのパーセル可能な配列クラスに関する問題

分類Dev

完了時のエスケープ文字に関するjlineの問題

分類Dev

ブートストラップ完了に関するOpenshift4.4の問題

分類Dev

プログラムが完了する前に終了する-forループでの並行性の問題-ゴルーチンが機能しない

分類Dev

ExecutorService関連の設計に関する質問

分類Dev

?に関するNULL可能型の問題:条件演算子

分類Dev

?に関するNULL可能型の問題:条件演算子

分類Dev

Reduxの使用に関する問題-Axiosで観察可能

分類Dev

typescriptでの呼び出し可能なタイプの関係に関する問題

分類Dev

これらのファイルは安全ですか、それとも将来問題になる可能性がありますか?

分類Dev

setOnLongClickListenerのダイアログの自動終了に関する問題

分類Dev

SequelizeJSの関係に関する問題

分類Dev

Flutterの正確な依存関係に関する問題

分類Dev

迅速な関数の呼び出しに関する問題

分類Dev

完了の問題

分類Dev

ContentEditableDIV内の編集不可能なスパンに関する選択と削除の問題

分類Dev

ホバー可能なドロップダウンメニューの項目の重複に関する問題

分類Dev

モーダル内の展開可能なテキストに関するCSSの問題

分類Dev

スクロール可能なビューアプリのクラッシュに関するTitaniumAndroidの問題

分類Dev

Javaの時間オフセットに関する解析不可能な日付の問題

Related 関連記事

  1. 1

    約束の完了に関する問題

  2. 2

    TableSorterの表示可能な行の初期数に関する問題

  3. 3

    完了可能な将来の失敗における情報の伝播

  4. 4

    ElementaryOS上のTexMakerでの完了に関する問題

  5. 5

    '!'の使用に関する問題 将来のリリースで削除されます

  6. 6

    将来の完了前に返す関数

  7. 7

    <Tab>を再利用可能な関数に配置するのに問題がある

  8. 8

    flatMapCompletableの後に完了可能なチェーンの問題

  9. 9

    Javaの最終変数の初期化に関する問題

  10. 10

    Androidのパーセル可能な配列クラスに関する問題

  11. 11

    完了時のエスケープ文字に関するjlineの問題

  12. 12

    ブートストラップ完了に関するOpenshift4.4の問題

  13. 13

    プログラムが完了する前に終了する-forループでの並行性の問題-ゴルーチンが機能しない

  14. 14

    ExecutorService関連の設計に関する質問

  15. 15

    ?に関するNULL可能型の問題:条件演算子

  16. 16

    ?に関するNULL可能型の問題:条件演算子

  17. 17

    Reduxの使用に関する問題-Axiosで観察可能

  18. 18

    typescriptでの呼び出し可能なタイプの関係に関する問題

  19. 19

    これらのファイルは安全ですか、それとも将来問題になる可能性がありますか?

  20. 20

    setOnLongClickListenerのダイアログの自動終了に関する問題

  21. 21

    SequelizeJSの関係に関する問題

  22. 22

    Flutterの正確な依存関係に関する問題

  23. 23

    迅速な関数の呼び出しに関する問題

  24. 24

    完了の問題

  25. 25

    ContentEditableDIV内の編集不可能なスパンに関する選択と削除の問題

  26. 26

    ホバー可能なドロップダウンメニューの項目の重複に関する問題

  27. 27

    モーダル内の展開可能なテキストに関するCSSの問題

  28. 28

    スクロール可能なビューアプリのクラッシュに関するTitaniumAndroidの問題

  29. 29

    Javaの時間オフセットに関する解析不可能な日付の問題

ホットタグ

アーカイブ