<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
之前寫過一個效能測試框架,只是針對單一的HTTP介面的測試,對於業務介面和非HTTP介面還無非適配,剛好前端時間工作中用到了,就更新了自己的測試框架,這次不再以請求為基礎,而是以方法為基礎,這樣就可以避免了單一性,有一個base類,然後其他的各種單一性請求在單獨寫一個適配類就好了,如果只是臨時用,直接重新實現base即可。
package com.fun.frame.thead; import com.fun.frame.SourceCode; import com.fun.frame.excute.Concurrent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import static com.fun.utils.Time.getTimeStamp; /** * 多執行緒任務基礎類別,可單獨使用 */ public abstract class ThreadBase<T> extends SourceCode implements Runnable { private static final Logger logger = LoggerFactory.getLogger(ThreadBase.class); /** * 任務請求執行次數 */ public int times; /** * 計數鎖 * <p> * 會在concurrent類裡面根據執行緒數自動設定 * </p> */ CountDownLatch countDownLatch; /** * 用於設定存取資源 */ public T t; public ThreadBase(T t) { this(); this.t = t; } public ThreadBase() { super(); } /** * groovy無法直接存取t,所以寫了這個方法 * * @return */ public String getT() { return t.toString(); } @Override public void run() { try { before(); List<Long> t = new ArrayList<>(); long ss = getTimeStamp(); for (int i = 0; i < times; i++) { long s = getTimeStamp(); doing(); long e = getTimeStamp(); t.add(e - s); } long ee = getTimeStamp(); logger.info("執行次數:{},總耗時:{}", times, ee - ss); Concurrent.allTimes.addAll(t); } catch (Exception e) { logger.warn("執行任務失敗!", e); } finally { after(); if (countDownLatch != null) countDownLatch.countDown(); } } /** * 執行待測方法的之前的準備 */ protected abstract void before(); /** * 待測方法 * * @throws Exception */ protected abstract void doing() throws Exception; /** * 執行待測方法後的處理 */ protected abstract void after(); public void setCountDownLatch(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } public void setTimes(int times) { this.times = times; } }
下面是幾個實現過的基礎類:
package com.fun.frame.thead; import com.fun.httpclient.ClientManage; import com.fun.httpclient.FanLibrary; import com.fun.httpclient.GCThread; import org.apache.http.HttpStatus; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; /** * http請求多執行緒類 */ public class RequestThread extends ThreadBase { static Logger logger = LoggerFactory.getLogger(RequestThread.class); /** * 請求 */ public HttpRequestBase request; /** * 單請求多執行緒多次任務構造方法 * * @param request 被執行的請求 * @param times 每個執行緒執行的次數 */ public RequestThread(HttpRequestBase request, int times) { this.request = request; this.times = times; } @Override public void before() { request.setConfig(FanLibrary.requestConfig); GCThread.starts(); } @Override protected void doing() throws Exception { getResponse(request); } @Override protected void after() { GCThread.stop(); } /** * 多次執行某個請求,但是不記錄紀錄檔,記錄方法用 loglong * <p>此方法只適應與單個請求的重複請求,對於有業務聯絡的請求暫時不能適配</p> * * @param request 請求 * @throws IOException */ void getResponse(HttpRequestBase request) throws IOException { CloseableHttpResponse response = ClientManage.httpsClient.execute(request); String content = FanLibrary.getContent(response); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) logger.warn("響應狀態碼:{},響應內容:{}", content, response.getStatusLine()); if (response != null) response.close(); } }
package com.fun.frame.thead; import com.fun.interfaces.IMySqlBasic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.SQLException; /** * 資料庫多執行緒類 */ public class QuerySqlThread extends ThreadBase { private static Logger logger = LoggerFactory.getLogger(QuerySqlThread.class); String sql; IMySqlBasic base; public QuerySqlThread(IMySqlBasic base, String sql, int times) { this.times = times; this.sql = sql; this.base = base; } @Override public void before() { base.getConnection(); } @Override protected void doing() throws SQLException { base.excuteQuerySql(sql); } @Override protected void after() { base.mySqlOver(); } }
package com.fun.frame.excute; import com.fun.bean.PerformanceResultBean; import com.fun.frame.Save; import com.fun.frame.SourceCode; import com.fun.frame.thead.ThreadBase; import com.fun.profile.Constant; import com.fun.utils.Time; import com.fun.utils.WriteRead; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Vector; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Concurrent { private static Logger logger = LoggerFactory.getLogger(Concurrent.class); /** * 執行緒任務 */ public ThreadBase thread; public List<ThreadBase> threads; public int num; public static Vector<Long> allTimes = new Vector<>(); ExecutorService executorService; CountDownLatch countDownLatch; /** * @param thread 執行緒任務 * @param num 執行緒數 */ public Concurrent(ThreadBase thread, int num) { this(num); this.thread = thread; } /** * @param threads 執行緒組 */ public Concurrent(List<ThreadBase> threads) { this(threads.size()); this.threads = threads; } public Concurrent(int num) { this.num = num; executorService = Executors.newFixedThreadPool(num); countDownLatch = new CountDownLatch(num); } /** * 執行多執行緒任務 */ public PerformanceResultBean start() { long start = Time.getTimeStamp(); for (int i = 0; i < num; i++) { ThreadBase thread = getThread(i); thread.setCountDownLatch(countDownLatch); executorService.execute(thread); } shutdownService(executorService, countDownLatch); long end = Time.getTimeStamp(); logger.info("總計" + num + "個執行緒,共用時:" + Time.getTimeDiffer(start, end) + "秒!"); return over(); } private static void shutdownService(ExecutorService executorService, CountDownLatch countDownLatch) { try { countDownLatch.await(); executorService.shutdown(); } catch (InterruptedException e) { logger.warn("執行緒池關閉失敗!", e); } } private PerformanceResultBean over() { Save.saveLongList(allTimes, num); return countQPS(num); } ThreadBase getThread(int i) { if (threads == null) return thread; return threads.get(i); } /** * 計算結果 * <p>此結果僅供參考</p> * * @param name 執行緒數 */ public static PerformanceResultBean countQPS(int name) { List<String> strings = WriteRead.readTxtFileByLine(Constant.LONG_Path + name + Constant.FILE_TYPE_LOG); int size = strings.size(); int sum = 0; for (int i = 0; i < size; i++) { int time = SourceCode.changeStringToInt(strings.get(i)); sum += time; } double v = 1000.0 * size * name / sum; PerformanceResultBean performanceResultBean = new PerformanceResultBean(name, size, sum / size, v); performanceResultBean.print(); return performanceResultBean; } }
redis實現類缺失,因為沒有遇到需要單獨實現的需求。
關於用程式碼還是用工具實現並行,我個人看法所有所長,單究其根本,必然是程式碼勝於工具,原因如下:門檻高,適應性強;貼近開發,利於調優。
效能測試,並行只是開始,只有一個好的開始才能進行效能資料分析,效能引數調優。所以不必拘泥於到底使用哪個工具那種語言,據我經驗來說:基本的測試需求都是能滿足的,只是實現的代價不同。
groovy是一種基於JVM的動態語言,我覺得最大的優勢有兩點
以上就是java效能測試框架手寫實現範例的詳細內容,更多關於java 效能測試框架的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45