亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java REST 優化數據結構訪問

Java REST 優化數據結構訪問

海綿寶寶撒 2022-05-12 18:35:02
我有一個 Java REST 應用程序,其中一個端點總是處理ConcurrentMap. 我正在做負載測試,當負載測試開始增加時真的很糟糕。為了提高應用程序的效率,我可以實施哪些策略?我應該使用 Jetty 線程,因為它是我正在使用的服務器嗎?還是主要是代碼?或兩者?成為瓶頸的方法如下。基本上我需要從給定文件中讀取一些行。我不能將它存儲在數據庫中,所以我想出了一個用 Map 進行處理的方法。但是,我知道對于大文件,不僅需要很長時間才能到達線路,而且我冒著 Map 在有很多條目時會消耗大量內存的風險......dict是ConcurrentMap。public String getLine(int lineNr) throws IllegalArgumentException {    if (lineNr > nrLines) {        throw new IllegalArgumentException();    }    if (dict.containsKey(lineNr)) {        return dict.get(lineNr);    }    synchronized (this) {        try (Stream<String> st = Files.lines(doc.toPath())            Optional<String> optionalLine = st.skip(lineNr - 1).findFirst();            if (optionalLine.isPresent()) {                dict.put(lineNr, optionalLine.get());            } else {                nrLines = nrLines > lineNr ? lineNr : nrLines;                throw new IllegalArgumentException();            }        } catch (IOException e) {            e.printStackTrace();        }        return cache.get(lineNr);    }
查看完整描述

2 回答

?
ibeautiful

TA貢獻1993條經驗 獲得超6個贊

該解決方案基于ConcurrentHashMap#computeIfAbsent,有兩個假設:

  1. 多個線程讀取同一個文件不是問題。

  2. 雖然文檔說由于阻塞,計算應該簡單而簡短,但我相信這只是相同密鑰(或存儲桶/條帶)訪問的問題,并且僅適用于更新(而不是讀取)?在這種情況下,這不是問題,因為我們要么成功計算了 value,要么 throw IllegalArgumentException。

使用它,我們通過將其作為放置密鑰所需的計算來實現每個密鑰只打開一次文件。

public String getLine(int lineNr) throws IllegalArgumentException {

        if (lineNr > nrLines) {

            throw new IllegalArgumentException();

        }

        return cache.computeIfAbsent(lineNr, (l) -> {

            try (Stream<String> st = Files.lines(path)) {

                Optional<String> optionalLine = st.skip(lineNr - 1).findFirst();

                if (optionalLine.isPresent()) {

                    return optionalLine.get();

                } else {

                    nrLines = nrLines > lineNr ? lineNr : nrLines;

                    throw new IllegalArgumentException();

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

            return null;

        });

    }

我通過產生 3 個線程來“驗證”第二個假設,其中:

  1. Thread1 通過無限循環(永遠阻塞)來計算密鑰 0。

  2. Thread2 嘗試放入鍵 0,但從未這樣做,因為 Thread1 阻塞。

  3. Thread3 嘗試放入鍵 1,并立即這樣做。

試試看,也許它有效,或者假設是錯誤的,它很糟糕。Map 在內部使用存儲桶,因此即使使用不同的鍵,計算也可能成為瓶頸,因為它鎖定了存儲桶/條帶。


查看完整回答
反對 回復 2022-05-12
?
絕地無雙

TA貢獻1946條經驗 獲得超4個贊

混ConcurrentMap在一起synchronized(this)可能不是正確的方法。包中的類java.util.concurrent是為特定用例設計的,并嘗試在內部優化同步。


相反,我建議先嘗試一個設計良好的緩存庫,看看性能是否足夠好。一個例子是咖啡因。根據Population docs,它為您提供了一種聲明如何加載數據的方法,即使是異步的:


AsyncLoadingCache<Key, Graph> cache = Caffeine.newBuilder()

    .maximumSize(10_000)

    .expireAfterWrite(10, TimeUnit.MINUTES)

    // Either: Build with a synchronous computation that is wrapped as asynchronous 

    .buildAsync(key -> createExpensiveGraph(key));

    // Or: Build with a asynchronous computation that returns a future

    .buildAsync((key, executor) -> createExpensiveGraphAsync(key, executor));


查看完整回答
反對 回復 2022-05-12
  • 2 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號