Почему Spring Boot такой медленный по сравнению с Node.js и Electron? - PullRequest
0 голосов
/ 02 июня 2019

Я работал над преобразованием вызовов API торговых приложений в Spring boot, чтобы использовать TWS API IB.Я подумал, что я могу держать все это в одном приложении.Первоначально я отправлял свои запросы через Angular 2, используя Electron.Однако, когда я перешел на Spring Boot, я заметил, что для возврата с Angular и Electron потребовалась секунда, которая заняла почти семь секунд.Мне трудно поверить, что Java медленнее, чем JavaScript.Я предполагаю, что на данный момент есть гораздо более быстрый способ сделать то, что я пытаюсь сделать на Java.Любая помощь будет оценена.Опять же, я просто ищу совет о том, как ускорить процесс здесь, если это вообще возможно.

  //Spring Boot Service Layer ---- 7 seconds :-o Seriously....

  public List<QuoteResponse> getGapUps(PriceParams p) {

    GapUpFilter guf = new GapUpFilter(p);
    int payloadSize = 200;
    StringBuilder payLoad = new StringBuilder();
    String stocks = this.getAllStocks();
    String[] sArr = stocks.split(",");
    LinkedList<String> ll = new LinkedList<String>( Arrays.asList(sArr));
    List<QuoteResponse> qrList = new ArrayList<QuoteResponse>();

    while (ll.size() > 0) {
        int i = 0;
        while (i < payloadSize && ll.size() > 0) {
            String stock = ll.pop();
            if (stock != null && stock.length() > 0 && ll.size() > 1) {
                payLoad.append(stock);
                payLoad.append(",");
            } 
            if (stock != null && stock.length() > 0 && ll.size() == 1) {
                payLoad.append(stock);
            } 
            i++;
        }
        QuoteResponseWrapper qrw = this.getPrice(payLoad.toString());
        QuoteResponse qr = guf.filterQuote(qrw.getQuoteResponse());
        if (qr.getResult().length > 0) {
            qrList.add(qr);
        }
        payLoad = new StringBuilder();
    }
    return qrList;
}


// Angular, Node.js with Electron - instantaneous

geMarketGaps(stocks: string, pFilter: PriceParams) {
this.securityService.getGaps(stocks).takeUntil(this.ngUnsubscribe).subscribe(lst => {

  for (let i = 0; i < lst.quoteResponse.result.length; i++) {
    try {

      const ppq = new PrePostQuote();
      ppq.symbol = lst.quoteResponse.result[i].symbol;

      try { ppq.pclose = lst.quoteResponse.result[i].regularMarketPrice.raw; } catch (e) {console.log(ppq.symbol, e); }
      try { ppq.cprice = lst.quoteResponse.result[i].regularMarketPrice.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.regularMarketPrice = lst.quoteResponse.result[i].regularMarketPrice.raw; } catch (e) { }
      try { ppq.ask = lst.quoteResponse.result[i].ask.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.bid = lst.quoteResponse.result[i].bid.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.shortName = lst.quoteResponse.result[i].shortName; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.sharesOutstanding = lst.quoteResponse.result[i].sharesOutstanding.fmt; } catch (e) { ppq.sharesOutstanding = '0'; }
      try { ppq.regularMarketVolume = lst.quoteResponse.result[i].regularMarketVolume.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.averageDailyVolume3Month = lst.quoteResponse.result[i].averageDailyVolume3Month.raw; } catch (e) {
        console.log(ppq.symbol, e); }
      try { ppq.epsTrailingTwelveMonths = lst.quoteResponse.result[i].epsTrailingTwelveMonths.raw; } catch (e) {
        console.log(ppq.symbol, e);  }
      try { ppq.priceToBook = lst.quoteResponse.result[i].priceToBook.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.askSize = lst.quoteResponse.result[i].askSize.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.bidSize = lst.quoteResponse.result[i].bidSize.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.fullExchangeName = lst.quoteResponse.result[i].fullExchangeName; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.regularMarketDayHigh = lst.quoteResponse.result[i].regularMarketDayHigh.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.regularMarketDayLow = lst.quoteResponse.result[i].regularMarketDayHigh.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.regularMarketOpen = lst.quoteResponse.result[i].regularMarketOpen.raw; } catch (e) {console.log(ppq.symbol, e);  }
      try { ppq.shortPotential = ppq.getShortPotential(1.2); } catch (e) { }

      try {
        ppq.marketState = lst.quoteResponse.result[i].marketState;
        // console.log('Market State: => ' + ppq.symbol, ppq.marketState);
      } catch (e) { }

      if (!ppq.marketState) {
        continue;
      }

      try { ppq.regularMarketChangePercent = lst.quoteResponse.result[i].regularMarketChangePercent.raw; } catch (e) { }
      try { ppq.pctraw = ppq.regularMarketChangePercent; } catch (e) { console.log(e); }

      if (ppq.marketState === 'REGULAR') {
        this.marketState = 'Reg Mkt';
      }

      if ((ppq.marketState === 'POST')
      && lst.quoteResponse.result[i].postMarketPrice) {
        try { ppq.cprice = lst.quoteResponse.result[i].postMarketPrice.raw; } catch (e) { console.log(e); }
        try { ppq.postMarketChangePercent
          = lst.quoteResponse.result[i].postMarketChangePercent.raw; } catch (e) { console.log(e); }
        try { ppq.pctgain = lst.quoteResponse.result[i].postMarketChangePercent.fmt; } catch (e) { console.log(e); }
        try { ppq.pctraw = ppq.postMarketChangePercent; } catch (e) { console.log(e); }
        this.marketState = 'Post Mkt';
      }

      if ((ppq.marketState === 'PREPRE' || ppq.marketState === 'POSTPOST'
      || ppq.marketState === 'CLOSED') && lst.quoteResponse.result[i].postMarketPrice) {
        try { ppq.cprice = lst.quoteResponse.result[i].postMarketPrice.raw; } catch (e) { console.log(e); }
        try { ppq.postMarketPrice = lst.quoteResponse.result[i].postMarketPrice.raw; } catch (e) { console.log(e); }
        try { ppq.postMarketChangePercent = ppq.getPrePrePctChange(); } catch (e) { console.log(e); }
        try { ppq.pctgain = ppq.getPrePrePctChange().toFixed(2) + '%'; } catch (e) { console.log(e); }
        try {
          ppq.pctraw = ppq.postMarketChangePercent;
          if ( ppq.pctraw > 5) {
            console.log(ppq.symbol + ' is greater than five percent');
          }
        } catch (e) { console.log(e); }
        this.marketState = 'Post Mkt';
      }

      if (ppq.marketState === 'PRE' && lst.quoteResponse.result[i].preMarketPrice) {
        try { ppq.cprice = parseFloat(lst.quoteResponse.result[i].preMarketPrice.raw); } catch (e) { console.log(e); }
        try { ppq.preMarketChangePercent
           = parseFloat(lst.quoteResponse.result[i].preMarketChangePercent.raw); } catch (e) { console.log(e); }
        try { ppq.pctgain = lst.quoteResponse.result[i].preMarketChangePercent.fmt; } catch (e) { console.log(e); }
        try { ppq.pctraw = ppq.preMarketChangePercent; } catch (e) { console.log(e); }
        this.marketState = 'Pre Mkt';
      }

      //////////////////////////////////////////////////////////////////////////////

      if (ppq.cprice >= pFilter.minPrice && ppq.cprice <= pFilter.maxPrice) {

        if (ppq.pctraw > 0
          && this.activeFilter === 'Market Movers'
          && (ppq.marketState === 'PRE' || ppq.marketState === 'PREPRE' || ppq.marketState === 'POST' || ppq.marketState === 'POSTPOST'
          || ppq.marketState === 'CLOSED'
        )
        ) {
          if (ppq.postMarketChangePercent >= pFilter.percent || ppq.preMarketChangePercent >= pFilter.percent ) {
            this.quotes.push(ppq);
          }
        }

        //////////////////////////////////////////////////////////////////////////////

        if (ppq.pctraw > 0 && this.activeFilter === 'Pct Gainers') {
          if (ppq.regularMarketChangePercent >= pFilter.percent) {
            this.quotes.push(ppq);
          }
        }

        //////////////////////////////////////////////////////////////////////////////

        if (ppq.pctraw < 0 && this.activeFilter === 'Market Losers'
        && (ppq.marketState === 'PRE' || ppq.marketState === 'PREPRE' || ppq.marketState === 'POST'
        || ppq.marketState === 'POSTPOST' || ppq.marketState === 'CLOSED')
      ) {
          if (ppq.postMarketChangePercent <= (pFilter.percent * -1) || ppq.preMarketChangePercent <= (pFilter.percent * -1)) {
            this.quotes.push(ppq);
          }
        }

        //////////////////////////////////////////////////////////////////////////////

        if (ppq.pctraw < 0 && this.activeFilter === 'Pct Losers') {
          if (ppq.regularMarketChangePercent <= (pFilter.percent * -1)) {
            this.quotes.push(ppq);
          }
        }

        //////////////////////////////////////////////////////////////////////////////
      }


    } catch (ex) {
      console.log(ex);
    }

  }
  this.recordsProcessed++;
  this.securityService.progressStart.next(this.recordsProcessed);

  if (this.recordCount === this.recordsProcessed) {
    this.showRecs = true;
  }

}, error => {
  this.recordsProcessed++;
  this.securityService.progressStart.next(this.recordsProcessed);
  if (this.recordCount === this.recordsProcessed) {
    this.showRecs = true;
  }
});

}

1 Ответ

0 голосов
/ 03 июня 2019

Для тех, кто заинтересован, CompleteableFuture было решением, которое я использовал. Мне удалось буквально сократить объем JSON размером более 7 МБ, буквально все данные котировок для всех фондовых бирж. Делая каждый запрос с использованием нового потока, запросы выполнялись параллельно, настолько быстро, что мне приходилось вводить небольшую задержку в вызовах, что, смехотворно, занимает большую часть времени. Я должен признать, я был из школы мысли, что Node.js определенно был быстрее из-за REPL и его неблокирующей архитектуры. Однако, после более глубокого погружения в Кроличью яму многопоточной пропасти Java, я бы настоятельно предостерег против таких утверждений.

@Async
public void loadPriceQuotes(String stocks) throws InterruptedException, ExecutionException {

    this.currentRecord++;
    System.out.println(this.currentRecord + " => " + this.recordCount);

    URLUtility urlUtil = new URLUtility();
    RestTemplate rt = new RestTemplate();

    CompletableFuture.supplyAsync(new Supplier<QuoteResponseWrapper>() {
        @Override
        public QuoteResponseWrapper get() {

            String url = urlUtil.getPriceURL(stocks);
            ResponseEntity<QuoteResponseWrapper> response = rt.getForEntity(url, QuoteResponseWrapper.class);

            for (Quote q: response.getBody().getQuoteResponse().getResult()) {
                SkyWalker.stockQuotes.add(q);
            }

            return response.getBody();
        }
    },executor);

    return;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...