实施 threads/callable 会使我的执行时间增加 50%,这是为什么?
Implementing threads/callable adds 50% to my execution time, why is this?
我目前正在学习多线程,但我在理解我的代码中出了什么问题时遇到了一些问题。
我试图通过调用我的函数 threadPopulateList()
来用随机数据填充两个列表。以我的理解,这应该并行启动两个线程,因为我调用了该方法两次。
但是,使用 threadmethod
时,我的执行时间增加了 ~50%。
代码:
public class Main {
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
long start=System.currentTimeMillis();
/**Populate lists after eachother gives --> 4211 ms */
// List<DATA>list1normal = populateNormal(9999999);
// List<DATA>list2normal = populateNormal(9999999);
/**Populate list simoultaniously/parralel --> 6500ms???*/
List<DATA>list1normal = threadPopulateList(9999999);
List<DATA>list2normal = threadPopulateList(9999999);
long stop = System.currentTimeMillis();
long executionTime = stop-start;
System.out.println(executionTime+" ms");
}
/**Method to populate list*/
static List<DATA> populateNormal(int amount){
List<DATA>data = new ArrayList<>();
Random rn = new Random();
for (int i = 0; i < amount; i++) {
data.add(new DATA(rn.nextInt(1000),rn.nextInt(1000), rn.nextInt(1000)));
}
return data;
}
/**Method to start a thread for each call so list will populate simoultiously*/
static List<DATA> threadPopulateList(int amount) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<DATA> data = new ArrayList<>();
Random rn = new Random();
Callable<List<DATA>> callable = () -> {
for (int i = 0; i < amount; i++) {
data.add(new DATA(rn.nextInt(1000), rn.nextInt(1000), rn.nextInt(1000)));
}
return data;
};
Future<List<DATA>> result = executor.submit(callable);
executor.shutdown();
return result.get();
}
}
Callable
是要执行的任务。你的代码只有一个Callable
所以它只能在一个线程上执行。
即使您创建了一个包含两个线程的ThreadPool
,但由于您只有一个任务,所以其中一个线程肯定是空闲的。
此外,您填写了两次列表,因此您的一项任务将是您填写一次列表时的两倍。
我会尝试创建两个 Callable
来处理列表中 1/2 的数据;然后安排他们两个。两者都完成后,将结果合并到最终的“输出”列表中。
您的解决方案只增加 50% 而不是 100% 的时间的原因是因为您的基准可能包括启动 JVM 和开始处理的时间。这意味着您对原始程序的整体分解可能是“执行时间 = 启动时间 + 处理时间”,其中启动时间约为执行时间的 1/2。
您实际上是在创建两个具有内部线程的序列化任务,但实际上并没有执行任何操作。如果你想并行化,你需要尝试更多类似这样的东西:
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
long start=System.nanoTime();
int amount = 9999999;
populateNormal(amount);
populateNormal(amount);
long stop = System.nanoTime();
System.out.println("Normal execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop - start)+"ms");
ExecutorService executor = Executors.newFixedThreadPool(2);
start = System.nanoTime();
final CountDownLatch latch = new CountDownLatch(2);
executor.submit(new Runnable() {
@Override
public void run() {
populateNormal(amount);
latch.countDown();
}
});
executor.submit(new Runnable() {
@Override
public void run() {
populateNormal(amount);
latch.countDown();
}
});
latch.await();
stop = System.nanoTime();
executor.shutdown();
System.out.println("Threaded execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop-start)+"ms");
}
我目前正在学习多线程,但我在理解我的代码中出了什么问题时遇到了一些问题。
我试图通过调用我的函数 threadPopulateList()
来用随机数据填充两个列表。以我的理解,这应该并行启动两个线程,因为我调用了该方法两次。
但是,使用 threadmethod
时,我的执行时间增加了 ~50%。
代码:
public class Main {
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
long start=System.currentTimeMillis();
/**Populate lists after eachother gives --> 4211 ms */
// List<DATA>list1normal = populateNormal(9999999);
// List<DATA>list2normal = populateNormal(9999999);
/**Populate list simoultaniously/parralel --> 6500ms???*/
List<DATA>list1normal = threadPopulateList(9999999);
List<DATA>list2normal = threadPopulateList(9999999);
long stop = System.currentTimeMillis();
long executionTime = stop-start;
System.out.println(executionTime+" ms");
}
/**Method to populate list*/
static List<DATA> populateNormal(int amount){
List<DATA>data = new ArrayList<>();
Random rn = new Random();
for (int i = 0; i < amount; i++) {
data.add(new DATA(rn.nextInt(1000),rn.nextInt(1000), rn.nextInt(1000)));
}
return data;
}
/**Method to start a thread for each call so list will populate simoultiously*/
static List<DATA> threadPopulateList(int amount) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<DATA> data = new ArrayList<>();
Random rn = new Random();
Callable<List<DATA>> callable = () -> {
for (int i = 0; i < amount; i++) {
data.add(new DATA(rn.nextInt(1000), rn.nextInt(1000), rn.nextInt(1000)));
}
return data;
};
Future<List<DATA>> result = executor.submit(callable);
executor.shutdown();
return result.get();
}
}
Callable
是要执行的任务。你的代码只有一个Callable
所以它只能在一个线程上执行。
即使您创建了一个包含两个线程的ThreadPool
,但由于您只有一个任务,所以其中一个线程肯定是空闲的。
此外,您填写了两次列表,因此您的一项任务将是您填写一次列表时的两倍。
我会尝试创建两个 Callable
来处理列表中 1/2 的数据;然后安排他们两个。两者都完成后,将结果合并到最终的“输出”列表中。
您的解决方案只增加 50% 而不是 100% 的时间的原因是因为您的基准可能包括启动 JVM 和开始处理的时间。这意味着您对原始程序的整体分解可能是“执行时间 = 启动时间 + 处理时间”,其中启动时间约为执行时间的 1/2。
您实际上是在创建两个具有内部线程的序列化任务,但实际上并没有执行任何操作。如果你想并行化,你需要尝试更多类似这样的东西:
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
long start=System.nanoTime();
int amount = 9999999;
populateNormal(amount);
populateNormal(amount);
long stop = System.nanoTime();
System.out.println("Normal execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop - start)+"ms");
ExecutorService executor = Executors.newFixedThreadPool(2);
start = System.nanoTime();
final CountDownLatch latch = new CountDownLatch(2);
executor.submit(new Runnable() {
@Override
public void run() {
populateNormal(amount);
latch.countDown();
}
});
executor.submit(new Runnable() {
@Override
public void run() {
populateNormal(amount);
latch.countDown();
}
});
latch.await();
stop = System.nanoTime();
executor.shutdown();
System.out.println("Threaded execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop-start)+"ms");
}