我想在java中编写一个简单的基准测试工具,它将启动x个线程并总共打满一次url。在java中编写一个简单的基准测试工具
它的实际任务部分将对网址发出Web请求,并发布XML文件。
所以我想要做的是,分拆50个线程,并保持点击的网址,直到我提出了10K请求。
有人可以解释如何做到这一点,我相信使用Executor服务是要走的路。
有些事情要考虑:
- 一旦线程完成,我猜它会立即运行正确的另一个任务是什么?
- 我需要线程返回,因为我必须跟踪成功/失败,应该在哪里存储(它必须是线程安全的)。
我想在java中编写一个简单的基准测试工具,它将启动x个线程并总共打满一次url。在java中编写一个简单的基准测试工具
它的实际任务部分将对网址发出Web请求,并发布XML文件。
所以我想要做的是,分拆50个线程,并保持点击的网址,直到我提出了10K请求。
有人可以解释如何做到这一点,我相信使用Executor服务是要走的路。
有些事情要考虑:
是,ExecutorService
是这个任务的最佳选择:
ExecutorService exec = Executors.newFixedThreadPool(50);
开始计时,并请提交10K任务是:
for(int i = 0; i < 10000; ++i) {
exec(new SubmitToUrlTask());
}
考虑使用的同一个实例(无状态或线程安全的),而不是在每次迭代中创建一个新线程。
在您必须等待执行完成结束:
exec.shutdown();
if(!exec.awaitTermination(1, TimeUnit.MINUTE)) {
throw new IllegalStateException("Waiting for too long, captain!");
}
现在停止计时。 awaitTermination()
块直到全部任务已完成,但不超过给定时间(示例中为1分钟)。
一旦一个线程完成,我猜它会立即运行另一个任务是否正确?
是的,ExecutorService
是一堆线程和任务队列。如果一个线程没有任何事情要做,它会从队列中获取第一个任务。
我需要线程返回,因为我必须跟踪成功/失败,应该在哪里存储它(它必须是线程安全的)。
您可以使用Callable<Boolean>
和Future<Boolean>
来跟踪结果。此外,如果您仅使用SubmitToUrlTask
的单个实例,则它可以具有两个变量AtomicInteger
类型,用于跟踪成功和失败。如果您不需要跟踪单个结果,这将简单得多。
这里是一个概述了一个战略,你可以使用注释的源代码:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class LoadGen {
/**
* Hits the given url for nRequests times on nUsers threads.
*
* @return LoadGen.Result object with status of the test
*/
public static Result generateLoad(final String url,
int nUsers, int nRequests) throws InterruptedException {
// A thread pool with one thread per simulated user
ExecutorService threadPool = Executors.newFixedThreadPool(nUsers);
// A latch awaited on by the user threads before the test is started
final CountDownLatch startSignal = new CountDownLatch(1);
// A latch awaited on by the main thread for all user threads
// to complete the test
final CountDownLatch doneSignal = new CountDownLatch(nUsers);
// The Result object for this test run
final Result result = new Result(nRequests);
// Submit one Runnable per simulated user
for (int i = 0; i < nUsers; i++) {
threadPool.submit(new Runnable() {
public void run() {
try {
// the Runnable awaits for the test to start
startSignal.await();
runSimulatedUser(url, result);
// indicate that this thread has completed
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
// Start all simulated user threads
startSignal.countDown();
// Wait for all simulated user threads to complete the test
doneSignal.await();
// Dispose all threads
threadPool.shutdownNow();
return result;
}
private static void runSimulatedUser(String url, Result result) {
// run repeatedly ..
while (true) {
try {
// hitting the URL, marking success and failure
// until nRequests requests are made in total
makeRequest(url);
if (! result.success()) {
break;
}
} catch (Exception e) {
e.printStackTrace();
if (! result.failure()) {
break;
}
}
}
}
private static void makeRequest(String url) {
// TODO: post the XML document to the URL etc
System.out.println("Making request");
}
public static class Result {
private final AtomicInteger nSuccess = new AtomicInteger();
private final AtomicInteger nFailure = new AtomicInteger();
private final AtomicInteger nTotal;
public Result(int nTotal) {
this.nTotal = new AtomicInteger(nTotal);
}
boolean success() {
nSuccess.incrementAndGet();
return nTotal.decrementAndGet() > 1;
}
boolean failure() {
nFailure.incrementAndGet();
return nTotal.decrementAndGet() > 1;
}
int getSuccessCount() {
return nSuccess.get();
}
int getFailureCount() {
return nFailure.get();
}
}
public static void main(String[] args) throws Exception {
// generate 10 requests on 2 threads
LoadGen.generateLoad("http://myurl.com", 2, 10);
}
}
你有什么这么远吗? – jtahlborn 2011-12-14 14:50:48
你确定你不是指“加载模拟器”吗?基准测试通常会涉及到一些速度问题,这听起来有点像“我的10k时间,并看看有多少请求失败”。我问,因为如果你想要一个基准,而不是压力测试,结果会有所不同。 – jefflunt 2011-12-14 14:50:49