tomcat jdbc SlowQueryReport的實現解讀

為什么80%的碼農都做不了架構師?>>> ??hot3.png

##序 tomcat提供了JdbcInterceptor可以用來監控jdbc的執行情況,默認提供了好幾個現成的interceptor可以用,SlowQueryReport以及SlowQueryReportJmx就是其中的兩個。

##JdbcInterceptor的基本原理

/*** Abstract class that is to be extended for implementations of interceptors.* Everytime an operation is called on the {@link java.sql.Connection} object the* {@link #invoke(Object, Method, Object[])} method on the interceptor will be called.* Interceptors are useful to change or improve behavior of the connection pool.<br>* Interceptors can receive a set of properties. Each sub class is responsible for parsing the properties during runtime when they* are needed or simply override the {@link #setProperties(Map)} method.* Properties arrive in a key-value pair of Strings as they were received through the configuration.* This method is called once per cached connection object when the object is first configured.** @version 1.0*/
public abstract class JdbcInterceptor implements InvocationHandler {/*** {@link java.sql.Connection#close()} method name*/public static final String CLOSE_VAL = "close";/*** {@link Object#toString()} method name*/public static final String TOSTRING_VAL = "toString";/*** {@link java.sql.Connection#isClosed()} method name*/public static final String ISCLOSED_VAL = "isClosed";/*** {@link javax.sql.PooledConnection#getConnection()} method name*/public static final String GETCONNECTION_VAL = "getConnection";/*** {@link java.sql.Wrapper#unwrap(Class)} method name*/public static final String UNWRAP_VAL = "unwrap";/*** {@link java.sql.Wrapper#isWrapperFor(Class)} method name*/public static final String ISWRAPPERFOR_VAL = "isWrapperFor";/*** {@link java.sql.Connection#isValid(int)} method name*/public static final String ISVALID_VAL = "isValid";/*** {@link java.lang.Object#equals(Object)}*/public static final String EQUALS_VAL = "equals";/*** {@link java.lang.Object#hashCode()}*/public static final String HASHCODE_VAL = "hashCode";/*** Properties for this interceptor.*/protected Map<String,InterceptorProperty> properties = null;/*** The next interceptor in the chain*/private volatile JdbcInterceptor next = null;/*** Property that decides how we do string comparison, default is to use* {@link String#equals(Object)}. If set to <code>false</code> then the* equality operator (==) is used.*/private boolean useEquals = true;/*** Public constructor for instantiation through reflection*/public JdbcInterceptor() {// NOOP}/*** Gets invoked each time an operation on {@link java.sql.Connection} is invoked.* {@inheritDoc}*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (getNext()!=null) return getNext().invoke(proxy,method,args);else throw new NullPointerException();}/*** Returns the next interceptor in the chain* @return the next interceptor in the chain*/public JdbcInterceptor getNext() {return next;}/*** configures the next interceptor in the chain* @param next The next chain item*/public void setNext(JdbcInterceptor next) {this.next = next;}/*** Performs a string comparison, using references unless the useEquals property is set to true.* @param name1 The first name* @param name2 The second name* @return true if name1 is equal to name2 based on {@link #useEquals}*/public boolean compare(String name1, String name2) {if (isUseEquals()) {return name1.equals(name2);} else {return name1==name2;}}/*** Compares a method name (String) to a method (Method)* {@link #compare(String,String)}* Uses reference comparison unless the useEquals property is set to true* @param methodName The method name* @param method The method* @return <code>true</code> if the name matches*/public boolean compare(String methodName, Method method) {return compare(methodName, method.getName());}/*** Gets called each time the connection is borrowed from the pool* This means that if an interceptor holds a reference to the connection* the interceptor can be reused for another connection.* <br>* This method may be called with null as both arguments when we are closing down the connection.* @param parent - the connection pool owning the connection* @param con - the pooled connection*/public abstract void reset(ConnectionPool parent, PooledConnection con);/*** Called when {@link java.sql.Connection#close()} is called on the underlying connection.* This is to notify the interceptors, that the physical connection has been released.* Implementation of this method should be thought through with care, as no actions should trigger an exception.* @param parent - the connection pool that this connection belongs to* @param con    - the pooled connection that holds this connection* @param finalizing - if this connection is finalizing. True means that the pooled connection will not reconnect the underlying connection*/public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {}/*** Returns the properties configured for this interceptor* @return the configured properties for this interceptor*/public Map<String,InterceptorProperty> getProperties() {return properties;}/*** Called during the creation of an interceptor* The properties can be set during the configuration of an interceptor* Override this method to perform type casts between string values and object properties* @param properties The properties*/public void setProperties(Map<String,InterceptorProperty> properties) {this.properties = properties;final String useEquals = "useEquals";InterceptorProperty p = properties.get(useEquals);if (p!=null) {setUseEquals(Boolean.parseBoolean(p.getValue()));}}/*** @return true if the compare method uses the Object.equals(Object) method*         false if comparison is done on a reference level*/public boolean isUseEquals() {return useEquals;}/*** Set to true if string comparisons (for the {@link #compare(String, Method)} and {@link #compare(String, String)} methods) should use the Object.equals(Object) method* The default is false* @param useEquals <code>true</code> if equals will be used for comparisons*/public void setUseEquals(boolean useEquals) {this.useEquals = useEquals;}/*** This method is invoked by a connection pool when the pool is closed.* Interceptor classes can override this method if they keep static* variables or other tracking means around.* <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>* @param pool - the pool that is being closed.*/public void poolClosed(ConnectionPool pool) {// NOOP}/*** This method is invoked by a connection pool when the pool is first started up, usually when the first connection is requested.* Interceptor classes can override this method if they keep static* variables or other tracking means around.* <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>* @param pool - the pool that is being closed.*/public void poolStarted(ConnectionPool pool) {// NOOP}}

可以看到它實現了InvocationHandler這個接口,也就是使用的是java內置的動態代理技術,主要是因為jdbc本身就是面向接口編程的,因而用java內置的動態代理是水到渠成的。

##ConnectionPool tomcat-jdbc-8.5.11-sources.jar!/org/apache/tomcat/jdbc/pool/ConnectionPool.java

/*** configures a pooled connection as a proxy.* This Proxy implements {@link java.sql.Connection} and {@link javax.sql.PooledConnection} interfaces.* All calls on {@link java.sql.Connection} methods will be propagated down to the actual JDBC connection except for the* {@link java.sql.Connection#close()} method.* @param con a {@link PooledConnection} to wrap in a Proxy* @return a {@link java.sql.Connection} object wrapping a pooled connection.* @throws SQLException if an interceptor can't be configured, if the proxy can't be instantiated*/protected Connection setupConnection(PooledConnection con) throws SQLException {//fetch previously cached interceptor proxy - one per connectionJdbcInterceptor handler = con.getHandler();if (handler==null) {//build the proxy handlerhandler = new ProxyConnection(this,con,getPoolProperties().isUseEquals());//set up the interceptor chainPoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();for (int i=proxies.length-1; i>=0; i--) {try {//create a new instanceJdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();//configure propertiesinterceptor.setProperties(proxies[i].getProperties());//setup the chaininterceptor.setNext(handler);//call resetinterceptor.reset(this, con);//configure the last one to be held by the connectionhandler = interceptor;}catch(Exception x) {SQLException sx = new SQLException("Unable to instantiate interceptor chain.");sx.initCause(x);throw sx;}}//cache handler for the next iterationcon.setHandler(handler);} else {JdbcInterceptor next = handler;//we have a cached handler, reset itwhile (next!=null) {next.reset(this, con);next = next.getNext();}}try {getProxyConstructor(con.getXAConnection() != null);//create the proxy//TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facadeConnection connection = null;if (getPoolProperties().getUseDisposableConnectionFacade() ) {connection = (Connection)proxyClassConstructor.newInstance(new Object[] { new DisposableConnectionFacade(handler) });} else {connection = (Connection)proxyClassConstructor.newInstance(new Object[] {handler});}//return the connectionreturn connection;}catch (Exception x) {SQLException s = new SQLException();s.initCause(x);throw s;}}

這里判斷有沒有interceptor,有的話,則創建ProxyConnection,然后構造interceptor的鏈 ##ProxyConnection

public class ProxyConnection extends JdbcInterceptor {protected PooledConnection connection = null;protected ConnectionPool pool = null;public PooledConnection getConnection() {return connection;}public void setConnection(PooledConnection connection) {this.connection = connection;}public ConnectionPool getPool() {return pool;}public void setPool(ConnectionPool pool) {this.pool = pool;}protected ProxyConnection(ConnectionPool parent, PooledConnection con,boolean useEquals) {pool = parent;connection = con;setUseEquals(useEquals);}@Overridepublic void reset(ConnectionPool parent, PooledConnection con) {this.pool = parent;this.connection = con;}public boolean isWrapperFor(Class<?> iface) {if (iface == XAConnection.class && connection.getXAConnection()!=null) {return true;} else {return (iface.isInstance(connection.getConnection()));}}public Object unwrap(Class<?> iface) throws SQLException {if (iface == PooledConnection.class) {return connection;}else if (iface == XAConnection.class) {return connection.getXAConnection();} else if (isWrapperFor(iface)) {return connection.getConnection();} else {throw new SQLException("Not a wrapper of "+iface.getName());}}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (compare(ISCLOSED_VAL,method)) {return Boolean.valueOf(isClosed());}if (compare(CLOSE_VAL,method)) {if (connection==null) return null; //noop for already closed.PooledConnection poolc = this.connection;this.connection = null;pool.returnConnection(poolc);return null;} else if (compare(TOSTRING_VAL,method)) {return this.toString();} else if (compare(GETCONNECTION_VAL,method) && connection!=null) {return connection.getConnection();} else if (method.getDeclaringClass().equals(XAConnection.class)) {try {return method.invoke(connection.getXAConnection(),args);}catch (Throwable t) {if (t instanceof InvocationTargetException) {throw t.getCause() != null ? t.getCause() : t;} else {throw t;}}}if (isClosed()) throw new SQLException("Connection has already been closed.");if (compare(UNWRAP_VAL,method)) {return unwrap((Class<?>)args[0]);} else if (compare(ISWRAPPERFOR_VAL,method)) {return Boolean.valueOf(this.isWrapperFor((Class<?>)args[0]));}try {PooledConnection poolc = connection;if (poolc!=null) {return method.invoke(poolc.getConnection(),args);} else {throw new SQLException("Connection has already been closed.");}}catch (Throwable t) {if (t instanceof InvocationTargetException) {throw t.getCause() != null ? t.getCause() : t;} else {throw t;}}}public boolean isClosed() {return connection==null || connection.isDiscarded();}public PooledConnection getDelegateConnection() {return connection;}public ConnectionPool getParentPool() {return pool;}@Overridepublic String toString() {return "ProxyConnection["+(connection!=null?connection.toString():"null")+"]";}}

ProxyConnection本身就是JdbcInterceptor,包裝了PooledConnection

##AbstractCreateStatementInterceptor 這個是JdbcInterceptor的一個比較重要的擴展,SlowQueryReport就是基于這個擴展的。這個定義了一些抽象方法供子類實現。

/*** Abstraction interceptor. This component intercepts all calls to create some type of SQL statement.* By extending this class, one can intercept queries and update statements by overriding the {@link #createStatement(Object, Method, Object[], Object, long)}* method.* @version 1.0*/
public abstract class  AbstractCreateStatementInterceptor extends JdbcInterceptor {protected static final String CREATE_STATEMENT      = "createStatement";protected static final int    CREATE_STATEMENT_IDX  = 0;protected static final String PREPARE_STATEMENT     = "prepareStatement";protected static final int    PREPARE_STATEMENT_IDX = 1;protected static final String PREPARE_CALL          = "prepareCall";protected static final int    PREPARE_CALL_IDX      = 2;protected static final String[] STATEMENT_TYPES = {CREATE_STATEMENT, PREPARE_STATEMENT, PREPARE_CALL};protected static final int    STATEMENT_TYPE_COUNT = STATEMENT_TYPES.length;protected static final String EXECUTE        = "execute";protected static final String EXECUTE_QUERY  = "executeQuery";protected static final String EXECUTE_UPDATE = "executeUpdate";protected static final String EXECUTE_BATCH  = "executeBatch";protected static final String[] EXECUTE_TYPES = {EXECUTE, EXECUTE_QUERY, EXECUTE_UPDATE, EXECUTE_BATCH};public  AbstractCreateStatementInterceptor() {super();}/*** {@inheritDoc}*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (compare(CLOSE_VAL,method)) {closeInvoked();return super.invoke(proxy, method, args);} else {boolean process = false;process = isStatement(method, process);if (process) {long start = System.currentTimeMillis();Object statement = super.invoke(proxy,method,args);long delta = System.currentTimeMillis() - start;return createStatement(proxy,method,args,statement, delta);} else {return super.invoke(proxy,method,args);}}}/*** This method will be invoked after a successful statement creation. This method can choose to return a wrapper* around the statement or return the statement itself.* If this method returns a wrapper then it should return a wrapper object that implements one of the following interfaces.* {@link java.sql.Statement}, {@link java.sql.PreparedStatement} or {@link java.sql.CallableStatement}* @param proxy the actual proxy object* @param method the method that was called. It will be one of the methods defined in {@link #STATEMENT_TYPES}* @param args the arguments to the method* @param statement the statement that the underlying connection created* @param time Elapsed time* @return a {@link java.sql.Statement} object*/public abstract Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time);/*** Method invoked when the operation {@link java.sql.Connection#close()} is invoked.*/public abstract void closeInvoked();/*** Returns true if the method that is being invoked matches one of the statement types.** @param method the method being invoked on the proxy* @param process boolean result used for recursion* @return returns true if the method name matched*/protected boolean isStatement(Method method, boolean process){return process(STATEMENT_TYPES, method, process);}/*** Returns true if the method that is being invoked matches one of the execute types.** @param method the method being invoked on the proxy* @param process boolean result used for recursion* @return returns true if the method name matched*/protected boolean isExecute(Method method, boolean process){return process(EXECUTE_TYPES, method, process);}/** Returns true if the method that is being invoked matches one of the method names passed in* @param names list of method names that we want to intercept* @param method the method being invoked on the proxy* @param process boolean result used for recursion* @return returns true if the method name matched*/protected boolean process(String[] names, Method method, boolean process) {final String name = method.getName();for (int i=0; (!process) && i<names.length; i++) {process = compare(names[i],name);}return process;}/*** no-op for this interceptor. no state is stored.*/@Overridepublic void reset(ConnectionPool parent, PooledConnection con) {// NOOP}
}

##AbstractQueryReport 主要實現了createStatement方法:

/*** Creates a statement interceptor to monitor query response times*/@Overridepublic Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {try {Object result = null;String name = method.getName();String sql = null;Constructor<?> constructor = null;if (compare(CREATE_STATEMENT,name)) {//createStatementconstructor = getConstructor(CREATE_STATEMENT_IDX,Statement.class);}else if (compare(PREPARE_STATEMENT,name)) {//prepareStatementsql = (String)args[0];constructor = getConstructor(PREPARE_STATEMENT_IDX,PreparedStatement.class);if (sql!=null) {prepareStatement(sql, time);}}else if (compare(PREPARE_CALL,name)) {//prepareCallsql = (String)args[0];constructor = getConstructor(PREPARE_CALL_IDX,CallableStatement.class);prepareCall(sql,time);}else {//do nothing, might be a future unsupported method//so we better bail out and let the system continuereturn statement;}result = constructor.newInstance(new Object[] { new StatementProxy(statement,sql) });return result;}catch (Exception x) {log.warn("Unable to create statement proxy for slow query report.",x);}return statement;}

這里同樣適用了jdk的動態代理,包裝了statement

/*** Class to measure query execute time**/protected class StatementProxy implements InvocationHandler {protected boolean closed = false;protected Object delegate;protected final String query;public StatementProxy(Object parent, String query) {this.delegate = parent;this.query = query;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//get the name of the method for comparisonfinal String name = method.getName();//was close invoked?boolean close = compare(JdbcInterceptor.CLOSE_VAL,name);//allow close to be called multiple timesif (close && closed) return null;//are we calling isClosed?if (compare(JdbcInterceptor.ISCLOSED_VAL,name)) return Boolean.valueOf(closed);//if we are calling anything else, bail outif (closed) throw new SQLException("Statement closed.");boolean process = false;//check to see if we are about to execute a queryprocess = isExecute( method, process);//if we are executing, get the current timelong start = (process)?System.currentTimeMillis():0;Object result =  null;try {//execute the queryresult =  method.invoke(delegate,args);}catch (Throwable t) {reportFailedQuery(query,args,name,start,t);if (t instanceof InvocationTargetException&& t.getCause() != null) {throw t.getCause();} else {throw t;}}//measure the timelong delta = (process)?(System.currentTimeMillis()-start):Long.MIN_VALUE;//see if we meet the requirements to measureif (delta>threshold) {try {//report the slow queryreportSlowQuery(query, args, name, start, delta);}catch (Exception t) {if (log.isWarnEnabled()) log.warn("Unable to process slow query",t);}} else if (process) {reportQuery(query, args, name, start, delta);}//perform close cleanupif (close) {closed=true;delegate = null;}return result;}}

這里記錄了sql的執行耗時,然后跟閾值對比,判斷是否記錄到slow query

轉載于:https://my.oschina.net/go4it/blog/1113969

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/456095.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/456095.shtml
英文地址,請注明出處:http://en.pswp.cn/news/456095.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【機器學習】Bagging和Boosting的區別(面試準備)

Baggging 和Boosting都是模型融合的方法&#xff0c;可以將弱分類器融合之后形成一個強分類器&#xff0c;而且融合之后的效果會比最好的弱分類器更好。 Bagging: 先介紹Bagging方法&#xff1a; Bagging即套袋法&#xff0c;其算法過程如下&#xff1a; 從原始樣本集中抽取訓…

python中的循環結構

循環結構 循環結構可以減少源程序重復書寫的工作量(代碼量)&#xff0c;用來描述重復執行某段算法的問題&#xff0c;這是程序設計中最能發揮計算機特長的程序結構。 Python中循環結構分為兩類&#xff0c;分別是 while 和 for .. in while 格式1&#xff1a; num1,num2 3…

線性判別結合源碼分析LDA原理

1. LDA的思想 LDA線性判別分析也是一種經典的降維方法&#xff0c;LDA是一種監督學習的降維技術&#xff0c;也就是說它的數據集的每個樣本是有類別輸出的。這點和PCA不同。PCA是不考慮樣本類別輸出的無監督降維技術。LDA的思想可以用一句話概括&#xff0c;就是“投影后類內方…

RIFF文件規范

RIFF文件規范Peter Lee 2007-10-02 摘要&#xff1a;RIFF全稱為資源互換文件格式&#xff08;Resources Interchange File Format&#xff09;&#xff0c;RIFF文件是windows環境下大部分多媒體文件遵循的一種文件結構&#xff0c;常見的如WAV文件、AVI文件等。RIFF可以看成一種…

FB宣布將回購60億美元股票 首席會計官將離職

11月19日消息&#xff0c;據美國媒體報道&#xff0c;Facebook宣布將回購60億美元股票&#xff0c;回購計劃將在明年第一季度開始實施。另外&#xff0c;該公司還宣布首席會計官賈斯艾特瓦爾將離職。 短期回購股票可使Facebook贏得時間&#xff0c;緩解投資長期項目如Instagram…

2017小目標

最美人間四月天&#xff0c;沒有三月的傲寒&#xff0c;沒有五月的燥熱&#xff0c;桃花剛偷去了紅&#xff0c;楊柳在風中扭著腰&#xff0c;櫻花正開的爛漫。工作繁忙之余。做一下深呼吸&#xff0c;沾衣欲濕杏花雨&#xff0c;吹面不含楊柳風。不知不覺2017第一季度已經結束…

【機器學習】feature_importances_ 參數源碼解析

在用sklearn的時候經常用到feature_importances_ 來做特征篩選&#xff0c;那這個屬性到底是啥呢。 分析源碼發現來源于每個base_estimator的決策樹的 feature_importances_ 由此發現計算邏輯來源于cython文件&#xff0c;這個文件可以在其github上查看源代碼 而在DecisionTree…

流行視頻格式講解

轉自 豪杰技術 http://www.herosoft.com 流行視頻格式講解 *. MPEG/.MPG/.DAT MPEG也是Motion Picture Experts Group 的縮寫。這類格式包括了 MPEG-1, MPEG-2 和 MPEG-4在內的多種視頻格式。MPEG-1相信是大家接觸得最多的了&#xff0c;因為目前其正在被廣泛地應用在 VCD…

歐盟通過最新《數據保護法》

歐洲議會近日通過了最新的《數據保護法》&#xff0c;用以保護消費者的數據和隱私。該法案是數字時代的首個新規&#xff0c;取代了一套20年前的、在互聯網發展初期階段構想的規則。新規規定&#xff0c;當企業所擁有的消費者相關數據遭遇黑客攻擊等泄露事件后&#xff0c;消費…

ajax 長輪詢

未完成&#xff0c;因為需要換成webscoket來做&#xff0c;該ajax長輪詢有待完善 function poll(){$.ajax({type:"POST",url:"ajax",async:true,data:{"receiverType":"single","receiverId":"${receiverId}",&qu…

python中變量的作用域

變量的作用域 變量的作用域就是指變量的有效范圍。 變量按照作用范圍分為兩類&#xff0c;分別是 全局變量 和 局部變量。 全局變量&#xff1a;在函數外部聲明的變量就是全局變量 有效范圍&#xff1a;全局變量在函數外部可以正常使用。全局變量在函數內部也可以正常使用(需要…

【機器學習】 關聯規則Apriori和mlxtend——推薦算法

引入&#xff1a; 啤酒與尿布的故事 關聯規律挖掘&#xff1a;從交易數據中發現&#xff1a;買了X 還會買Y 的規則 關聯規律挖掘‘購物籃分析’Market Basket Analysis&#xff08;MBA&#xff09; 關聯規律->應用于推薦系統 1. 關聯規則代碼演示 使用的是mlxtend.frequent…

預防和檢測如日中天?事件響應表示不服

近些年&#xff0c;企業安全工作的關注點&#xff0c;一直聚焦在如何預防黑客攻擊。但是&#xff0c;頻發的大型跨國企業的數據泄露事件表明&#xff0c;即使是對網絡安全更為重視&#xff0c;同時也投入了更多成本的金融業&#xff0c;也明白了“無論做了怎樣的安全防護&#…

python中的內部函數和閉包函數

內部函數 在函數內部聲明的函數就是內部函數。 格式&#xff1a; def 函數名():局部變量...def 內部函數名():Python功能代碼...示例&#xff1a; def funName():name dragon#定義一個內部函數def inner():print(我是內部函數)‘’‘注釋&#xff1a; 1.內部函數的本質就是局…

【機器學習】K-Means(非監督學習)學習及實例使用其將圖片壓縮

非監督學習之k-means K-means通常被稱為勞埃德算法&#xff0c;這在數據聚類中是最經典的&#xff0c;也是相對容易理解的模型。算法執行的過程分為4個階段。 1、從數據中選擇k個對象作為初始聚類中心; 2、計算每個聚類對象到聚類中心的距離來劃分&#xff1b; 3、再次計算…

CloudCC CRM:物聯網必將成為CRM的推動力

CRM熱門話題背后的主要推動力包括云、社交、移動和大數據&#xff0c;CloudCC CRM認為物聯網必將成為CRM的推動力&#xff0c;也就是傳感器將事物連接到互聯網&#xff0c;創建之前我們從未想到的新型服務。 社交&#xff1a;在銷售、市場和客戶服務部門&#xff0c;營銷人員正…

關于Video Renderer和Overlay Mixer

原文作者: 陸其明 整理日期: 2004/12/27 大家知道&#xff0c;Video Renderer (VR)是接收RGB/YUV裸數據&#xff0c;然后在顯示器上顯示的Filter。為提高計算機畫圖性能&#xff0c;根據你計算機顯卡的能力&#xff0c;VR會優先使用DirectDraw以及Overlay表面&#xff1b;如果…

【tensorflow】tensorflow -gpu安裝及jupyter環境更改

tensorflow -gpu安裝 首先&#xff0c;安裝Anoconda 1. 官網下載點我&#xff1a;2.安裝 點擊 python 3.6 version自動下載x64版&#xff0c;下載好之后&#xff0c;然后安裝。 如圖&#xff0c;打上勾之后&#xff0c;一路next3.打開終端 1&#xff09;輸入conda –-version …

張震博士:SDT是未來安防發展方向

如何挖掘安防大數據價值是未來發展方向 發展實踐證明&#xff0c;科技強警已經成為未來發展的必然選擇&#xff0c;發展科技強警&#xff0c;必須用技術實力說話。作為科技強警的重要組成部分&#xff0c;安防視頻非常重要&#xff0c;但是&#xff0c;目前&#xff0c;安防視頻…

關于虛擬機第二塊網卡eth1(僅主機模式)的配置問題

這里發生了一個想不明白的事情&#xff0c;我的真機的網卡上面并沒有192.168.100.0網段的網卡 但是我在虛擬機上面添加了一塊網卡&#xff08;僅主機模式&#xff09;eth1 并配置為192.168.100.60&#xff08;配置文件已經寫好&#xff09; 開機卻能用eth1連接上xhell&#xff…