簡體   English   中英

如何使用執行器服務處理實時數據?

[英]how to process real time data with executor service?

我的目標是使用ScheduledExecutorService收集實時數據,每 5 秒掃描一次數據庫,捕獲任何新數據點,然后進行一些計算。 數據在不確定的時間內到達數據庫(即 2 秒內 3 個數據點或 2 秒內 5 個數據點)

對於每一個傳入的數據點,計算時間要求為 10 秒。 我的問題是:如何在不干擾計算方面的同時更新我的捕獲數據堆棧。 我也認為:

  • 因為我不能使用 for 循環,因為實時數據無法以可預測的方式到達並且數據不是“離線”格式
  • 計算完成,沒有新數據到來,這種情況如何處理?
  • 我不打算在計算部分使用第二個ScheduledExecutorService ,因為計算時間比掃描對應的時間長。

有什么我可以參考的實現嗎? 我沒有主意,我沒有樣本,而是偽格式。 我嘗試可怕地使用 while-loop,然后通過 pid 進程將其殺死,摘錄如下:

        //how to process real time data
        while(true) {
            if(calculationBegins) { //when first data point arrives
                while(true) {
                    int oldDataSize = RealTimeData.size();
                    for(int i = 0; i < oldDataSize; i++) {
                        //
                        //complex calculation that takes 10 sec
                        //
                    }
                    
                    //if new data arrived, break out and proceed calculation
                    while(true){
                        if(RealTimeData.size() > oldDataSize) break; //ScheduledExecutor will update the new size
                    }
                }
            }
        }

這是完整的代碼(兩個文件)

  1. 測試.java:
package test;

import static test.HikariCPDataSource.calculationBegins;
import static test.HikariCPDataSource.RealTimeData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


public class Test {

    static List<String> capture = new ArrayList<String>();

    public static void main(String[] args) {
        
        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

        Runnable extract = () -> {
            HikariCPDataSource.getData(args[0]);
        };

        service.scheduleAtFixedRate(extract, 0, 5, TimeUnit.SECONDS);
        
        
        //how to process real time data
        while(true) {
            if(calculationBegins) {
                while(true) {
                    int oldDataSize = RealTimeData.size();
                    for(int i = 0; i < oldDataSize; i++) {
                        //
                        //complex calculation that takes 10 sec
                        //
                    }
                    
                    //if new data arrived, break out and proceed calculation
                    while(true){
                        if(RealTimeData.size() > oldDataSize) break;
                    }
                }
            }
        }
        
    }
}
  1. HikariCPDataSource.java
package test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;


public class HikariCPDataSource {
    
    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;
    public static boolean calculationBegins = false; //true: start calculation when the very first data points arrives
    public static List<String> RealTimeData = new ArrayList<>(); //capture real time data from database
    public static int index = 0;
    static {
        config.setJdbcUrl("jdbc:mysql://127.0.0.1/testdb");
        config.setUsername("root");
        config.setPassword("caspo123");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.setMaximumPoolSize(2);
        config.setMinimumIdle(1);
        config.setIdleTimeout(0);
        config.setMaxLifetime(0);
        ds = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    private HikariCPDataSource(){}

    public static void setCalculationBegins() {
            calculationBegins = true;
    }
    
    public static int getSizeHikariScout(){
        return(RealTimeData.size());
    }
    
    public static int getIndex() {
        return(index);
    }
    
    public static void resetIndex(int updateIndex) {
        index = index + updateIndex;
    }
    
    public static void getData(String input1) {
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        String output = null;
        
        try{
            con = ds.getConnection();
            pstmt = con.prepareStatement("SELECT column1, column2 FROM testdb where id = ? and index > ?");
            pstmt.setString(1, input1);
            pstmt.setInt(1, getIndex());
            resultSet = pstmt.executeQuery();
            int indexCount = 0;
            while (resultSet.next()){
                    if(!calculationBegins) setCalculationBegins(); 
                    output = String.join(",", resultSet.getString("column1"), resultSet.getString("column2"));
                    RealTimeData.add(output);
                    indexCount = indexCount + 1;
            }
            resetIndex(indexCount);
        } catch (SQLException e){
            e.printStackTrace();
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
}

我在這里看到的一種解決方案(實際上我自己也做過類似的事情)是創建兩個ExecutorService 一個是ScheduledExecutorService ,第二個是常規的FixedThreadPool Executor。

第一個將定期運行,假設每 3 秒運行一次。 它只會掃描數據庫中的新數據點,如果找到一些,它會將任務提交/排隊到另一個執行器。

第二個 Executor 將執行所有計算以及您想要對數據執行的任何其他操作。 提交的任務將排隊等待執行,一旦有空閑線程就會完成。

這樣,所有線程管理和任務隊列處理都由 Executors 完成,您不必自己擔心。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM