Browse Source

parallelize read queries

denkab 10 years ago
parent
commit
137f75e883

+ 22 - 0
frameworks/Java/spring/src/main/java/com/techempower/spring/Common.java

@@ -0,0 +1,22 @@
+package com.techempower.spring;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * User: Denis Baranov
+ * Date: 2/18/15
+ */
+public class Common {
+
+    private static final int cpuCount = Runtime.getRuntime().availableProcessors();
+
+    // todo: parameterize multipliers
+    public static ExecutorService EXECUTOR = new ThreadPoolExecutor(
+        cpuCount * 2, cpuCount * 25, 200, TimeUnit.MILLISECONDS,
+        new LinkedBlockingQueue<Runnable>(cpuCount * 100),
+        new ThreadPoolExecutor.CallerRunsPolicy());
+
+}

+ 31 - 9
frameworks/Java/spring/src/main/java/com/techempower/spring/web/WorldDatabaseController.java

@@ -3,9 +3,14 @@ package com.techempower.spring.web;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.Random;
 import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 
 
+import com.techempower.spring.Common;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
@@ -28,16 +33,33 @@ final class WorldDatabaseController {
 	}
 	}
 
 
 	@RequestMapping(value = "/queries", produces = "application/json")
 	@RequestMapping(value = "/queries", produces = "application/json")
+	@Transactional(readOnly = true)
 	List<World> multipleQueries(@RequestParam(value="queries", required=false, defaultValue="1") String rawQueryCount) {
 	List<World> multipleQueries(@RequestParam(value="queries", required=false, defaultValue="1") String rawQueryCount) {
 		Integer queryCount = boundQueryCount(rawQueryCount);
 		Integer queryCount = boundQueryCount(rawQueryCount);
 
 
-		List<World> worlds = new ArrayList<World>(queryCount);
-		Random random = ThreadLocalRandom.current();
+		List<World> worlds = new ArrayList<>(queryCount);
+		List<Future<World>> wfs = new ArrayList<>(queryCount);
 
 
+		// it gets better with Java 8, promise!
 		for (int i = 0; i < queryCount; i++) {
 		for (int i = 0; i < queryCount; i++) {
-			worlds.add(this.worldRepository.findOne(random.nextInt(DB_ROWS) + 1));
+			wfs.add(
+				Common.EXECUTOR.submit(
+					new Callable<World>() {
+						@Override
+						public World call() throws Exception {
+							return worldRepository.findOne(
+								ThreadLocalRandom.current().nextInt(DB_ROWS) + 1);
+						}
+					}));
 		}
 		}
 
 
+		for (Future<World> wf: wfs) {
+			try {
+				worlds.add(wf.get());
+			} catch (InterruptedException | ExecutionException e) {
+				throw new RuntimeException(e);
+			}
+		}
 		return worlds;
 		return worlds;
 	}
 	}
 
 
@@ -59,12 +81,12 @@ final class WorldDatabaseController {
 	}
 	}
 
 
 	private Integer boundQueryCount(final String rawString) {
 	private Integer boundQueryCount(final String rawString) {
-                Integer raw;
-                try {
-                       raw = Integer.parseInt(rawString);
-                } catch (NumberFormatException e) {
-                       raw = null;
-                } 
+        Integer raw;
+        try {
+           raw = Integer.parseInt(rawString);
+        } catch (NumberFormatException e) {
+           raw = null;
+        }
 		if (raw == null || raw < 1) {
 		if (raw == null || raw < 1) {
 			return 1;
 			return 1;
 		} else if (raw > 500) {
 		} else if (raw > 500) {