异步的AsyncHttpClient使用详解

2023-10-27

背景

       前面的一篇文章【同步的HttpClient使用详解】中,提到了服务端通进行网络请求的方式。也讲述了在并发量大的情况下使用HttpClient的连接池来提高性能。此方法虽然很有效果,但是当访问量极大或网络不好的情况下也会出现某些网络请求慢导致其它请求阻塞的情况,为此本文引入了异步的HttpClient包,将网络请求变成一个异步的请求,不影响其它的请求。

异步httpClient需要的jar包

 

 <!-- httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.6</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpasyncclient</artifactId>
            <version>4.1.3</version>
        </dependency>

注意:由于异步的HttpClient比较新,所以尽量使用该文中的版本jar包,或以上版本

使用方法

为了更好的使用,在这里简单的使用了工厂模式。将同步的httpclient与异步的httpclient通过工厂进行实例化

1、定义异步的httpclient

 

package com.studyproject.httpclient;

import java.nio.charset.CodingErrorAction;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Lookup;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;

/**
 * 异步的HTTP请求对象,可设置代理
 */
public class HttpAsyncClient {

	private static int socketTimeout = 5000;// 设置等待数据超时时间5秒钟 根据业务调整

	private static int connectTimeout = 2000;// 连接超时

	private static int poolSize = 3000;// 连接池最大连接数

	private static int maxPerRoute = 1500;// 每个主机的并发最多只有1500,如果后端保有一台应用机就配置3000

	// http代理相关参数
	private String host = "";
	private int port = 0;
	private String username = "";
	private String password = "";

	// 异步httpclient
	private CloseableHttpAsyncClient asyncHttpClient;

	// 异步加代理的httpclient
	private CloseableHttpAsyncClient proxyAsyncHttpClient;

	public HttpAsyncClient() {
		try {
			this.asyncHttpClient = createAsyncClient(false);
			this.proxyAsyncHttpClient = createAsyncClient(true);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public CloseableHttpAsyncClient createAsyncClient(boolean proxy)
			throws KeyManagementException, UnrecoverableKeyException,
			NoSuchAlgorithmException, KeyStoreException,
			MalformedChallengeException, IOReactorException {

		SSLContext sslcontext = SSLContexts.createDefault();

		UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
				username, password);

		CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
		credentialsProvider.setCredentials(AuthScope.ANY, credentials);

		// 设置协议http和https对应的处理socket链接工厂的对象
		Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder
				.<SchemeIOSessionStrategy> create()
				.register("http", NoopIOSessionStrategy.INSTANCE)
				.register("https", new SSLIOSessionStrategy(sslcontext))
				.build();

		// 配置io线程
		IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
				.setIoThreadCount(Runtime.getRuntime().availableProcessors())
				.build();
		// 设置连接池大小
		ConnectingIOReactor ioReactor;
		ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
		PoolingNHttpClientConnectionManager conMgr = new PoolingNHttpClientConnectionManager(
				ioReactor, null, sessionStrategyRegistry, null);

		if (poolSize > 0) {
			conMgr.setMaxTotal(poolSize);
		}

        //每个主机最大的并发量
		if (maxPerRoute > 0) {
			conMgr.setDefaultMaxPerRoute(maxPerRoute);
		} else {
			conMgr.setDefaultMaxPerRoute(10);
		}
       
        //连接相关配置
		ConnectionConfig connectionConfig = ConnectionConfig.custom()
				.setMalformedInputAction(CodingErrorAction.IGNORE)
				.setUnmappableInputAction(CodingErrorAction.IGNORE)
				.setCharset(Consts.UTF_8).build();

		//请求相关配置
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectTimeout(connectTimeout)
				.setSocketTimeout(socketTimeout).build();

       
		Lookup<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder
				.<AuthSchemeProvider> create()
				.register(AuthSchemes.BASIC, new BasicSchemeFactory())
				.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
				.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
				.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
				.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
				.build();
		conMgr.setDefaultConnectionConfig(connectionConfig);

		if (proxy) {
			return HttpAsyncClients.custom().setConnectionManager(conMgr)
					.setDefaultCredentialsProvider(credentialsProvider)
					.setDefaultAuthSchemeRegistry(authSchemeRegistry)
					.setProxy(new HttpHost(host, port))
					.setDefaultCookieStore(new BasicCookieStore())
					.setDefaultRequestConfig(requestConfig).build();
		} else {
			return HttpAsyncClients.custom().setConnectionManager(conMgr)
					.setDefaultCredentialsProvider(credentialsProvider)
					.setDefaultAuthSchemeRegistry(authSchemeRegistry)
					.setDefaultCookieStore(new BasicCookieStore()).build();
		}

	}

	public CloseableHttpAsyncClient getAsyncHttpClient() {
		return asyncHttpClient;
	}

	public CloseableHttpAsyncClient getProxyAsyncHttpClient() {
		return proxyAsyncHttpClient;
	}
}


2、定义同步的httpclient

 

 

package com.studyproject.httpclient;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 同步的HTTP请求对象,支持post与get方法以及可设置代理
 */
public class HttpSyncClient {

	private Logger logger = LoggerFactory.getLogger(HttpSyncClient.class);

	private static int socketTimeout = 1000;// 设置等待数据超时时间5秒钟 根据业务调整

	private static int connectTimeout = 2000;// 连接超时

	private static int maxConnNum = 4000;// 连接池最大连接数

	private static int maxPerRoute = 1500;// 每个主机的并发最多只有1500

	private static PoolingClientConnectionManager cm;

	private static HttpParams httpParams;

	private static final String DEFAULT_ENCODING = Charset.defaultCharset()
			.name();

	// proxy代理相关配置
	private String host = "";
	private int port = 0;
	private String username = "";
	private String password = "";

	private DefaultHttpClient httpClient;

	private DefaultHttpClient proxyHttpClient;

	// 应用启动的时候就应该执行的方法
	public HttpSyncClient() {

		this.httpClient = createClient(false);

		this.proxyHttpClient = createClient(true);
	}

	public DefaultHttpClient createClient(boolean proxy) {

		SchemeRegistry sr = new SchemeRegistry();
		sr.register(new Scheme("http", 80, PlainSocketFactory
				.getSocketFactory()));
		SSLSocketFactory sslFactory;
		try {
			SSLContext sslContext = SSLContext.getInstance("SSL");
			X509TrustManager tm = new X509TrustManager() {
				@Override
				public void checkClientTrusted(X509Certificate[] chain,
						String authType) throws CertificateException {
				}

				@Override
				public void checkServerTrusted(X509Certificate[] chain,
						String authType) throws CertificateException {
				}

				@Override
				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}
			};
			sslContext.init(null, new TrustManager[] { tm },
					new java.security.SecureRandom());
			sslFactory = new SSLSocketFactory(sslContext,
					SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			sr.register(new Scheme("https", 443, sslFactory));
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 初始化连接池
		cm = new PoolingClientConnectionManager(sr);
		cm.setMaxTotal(maxConnNum);
		cm.setDefaultMaxPerRoute(maxPerRoute);
		httpParams = new BasicHttpParams();
		httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
				HttpVersion.HTTP_1_1);
		httpParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
				connectTimeout);// 请求超时时间
		httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT,
				socketTimeout);// 读取数据超时时间
		// 如果启用了NoDelay策略,httpclient和站点之间传输数据时将会尽可能及时地将发送缓冲区中的数据发送出去、而不考虑网络带宽的利用率,这个策略适合对实时性要求高的场景
		httpParams.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);
		httpParams.setBooleanParameter(
				CoreConnectionPNames.STALE_CONNECTION_CHECK, true);

		DefaultHttpClient httpclient = new DefaultHttpClient(cm, httpParams);

		if (proxy) {
			httpclient.getCredentialsProvider().setCredentials(
					new AuthScope(host, port),
					new UsernamePasswordCredentials(username, password));
		}

		return httpclient;

	}

	public DefaultHttpClient getHttpClient() {
		return httpClient;
	}

	public DefaultHttpClient getProxyClient() {
		return proxyHttpClient;
	}

	public String httpGet(String url, List<BasicNameValuePair> parameters) {

		DefaultHttpClient client = getHttpClient();// 默认会到池中查询可用的连接,如果没有就新建
		HttpGet getMethod = null;
		String returnValue = "";
		try {
			getMethod = new HttpGet(url);

			if (null != parameters) {
				String params = EntityUtils.toString(new UrlEncodedFormEntity(
						parameters, DEFAULT_ENCODING));
				getMethod.setURI(new URI(getMethod.getURI().toString() + "?"
						+ params));
				logger.debug("httpGet-getUrl:{}", getMethod.getURI());
			}

			HttpResponse response = client.execute(getMethod);
			int statusCode = response.getStatusLine().getStatusCode();

			if (statusCode == 200) {
				HttpEntity he = response.getEntity();
				returnValue = new String(EntityUtils.toByteArray(he),
						DEFAULT_ENCODING);
				return returnValue;
			}

		} catch (UnsupportedEncodingException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpGet Send Error,Code error:" + e.getMessage());
		} catch (ClientProtocolException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpGet Send Error,Protocol error:" + e.getMessage());
		} catch (IOException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpGet Send Error,IO error:" + e.getMessage());
		} catch (URISyntaxException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpGet Send Error,IO error:" + e.getMessage());
		} finally {// 释放连接,将连接放回到连接池
			getMethod.releaseConnection();

		}
		return returnValue;

	}

	public String httpPost(String url, List<BasicNameValuePair> parameters,
			String requestBody) {

		DefaultHttpClient client = getHttpClient();// 默认会到池中查询可用的连接,如果没有就新建
		HttpPost postMethod = null;
		String returnValue = "";
		try {
			postMethod = new HttpPost(url);

			if (null != parameters) {
				String params = EntityUtils.toString(new UrlEncodedFormEntity(
						parameters, DEFAULT_ENCODING));
				postMethod.setURI(new URI(postMethod.getURI().toString() + "?"
						+ params));
				logger.debug("httpPost-getUrl:{}", postMethod.getURI());
			}

			if (StringUtils.isNotBlank(requestBody)) {
				StringEntity se = new StringEntity(requestBody,
						DEFAULT_ENCODING);
				postMethod.setEntity(se);
			}

			HttpResponse response = client.execute(postMethod);
			int statusCode = response.getStatusLine().getStatusCode();

			if (statusCode == 200) {
				HttpEntity he = response.getEntity();
				returnValue = new String(EntityUtils.toByteArray(he),
						DEFAULT_ENCODING);
				return returnValue;
			}

		} catch (UnsupportedEncodingException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpPost Send Error,Code error:" + e.getMessage());
		} catch (ClientProtocolException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpPost Send Error,Protocol error:" + e.getMessage());
		} catch (IOException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpPost Send Error,IO error:" + e.getMessage());
		} catch (URISyntaxException e) {
			logger.error(Thread.currentThread().getName()
					+ "httpPost Send Error,IO error:" + e.getMessage());
		} finally {// 释放连接,将连接放回到连接池
			postMethod.releaseConnection();
			// 释放池子中的空闲连接
			// client.getConnectionManager().closeIdleConnections(30L,
			// TimeUnit.MILLISECONDS);
		}
		return returnValue;

	}
}


3、定义httpClient工厂类

 

 

package com.studyproject.httpclient;

/**
 * 
 * httpclient 工厂类
 * */
public class HttpClientFactory {

	private static HttpAsyncClient httpAsyncClient = new HttpAsyncClient();

	private static HttpSyncClient httpSyncClient = new HttpSyncClient();

	private HttpClientFactory() {
	}

	private static HttpClientFactory httpClientFactory = new HttpClientFactory();

	public static HttpClientFactory getInstance() {

		return httpClientFactory;

	}

	public HttpAsyncClient getHttpAsyncClientPool() {
		return httpAsyncClient;
	}

	public HttpSyncClient getHttpSyncClientPool() {
		return httpSyncClient;
	}

}


4、定义httpclient业务逻辑处理类,对外的方法可以通过这个类来封装

 

 

 

 

package com.studyproject.httpclient;

import java.io.IOException;
import java.net.URI;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * http client 业务逻辑处理类
 * */
public class HttpClientService {

	private static Logger LOG = LoggerFactory
			.getLogger(HttpClientService.class);

	protected void exeAsyncReq(String baseUrl, boolean isPost,
			List<BasicNameValuePair> urlParams,
			List<BasicNameValuePair> postBody, FutureCallback callback)
			throws Exception {

		if (baseUrl == null) {
			LOG.warn("we don't have base url, check config");
			throw new Exception("missing base url");
		}

		HttpRequestBase httpMethod;
		CloseableHttpAsyncClient hc = null;

		try {
			hc = HttpClientFactory.getInstance().getHttpAsyncClientPool()
					.getAsyncHttpClient();

			hc.start();

			HttpClientContext localContext = HttpClientContext.create();
			BasicCookieStore cookieStore = new BasicCookieStore();

			if (isPost) {
				httpMethod = new HttpPost(baseUrl);

				if (null != postBody) {
					LOG.debug("exeAsyncReq post postBody={}", postBody);
					UrlEncodedFormEntity entity = new UrlEncodedFormEntity(
							postBody, "UTF-8");
					((HttpPost) httpMethod).setEntity(entity);
				}

				if (null != urlParams) {

					String getUrl = EntityUtils
							.toString(new UrlEncodedFormEntity(urlParams));

					httpMethod.setURI(new URI(httpMethod.getURI().toString()
							+ "?" + getUrl));
				}

			} else {

				httpMethod = new HttpGet(baseUrl);

				if (null != urlParams) {

					String getUrl = EntityUtils
							.toString(new UrlEncodedFormEntity(urlParams));

					httpMethod.setURI(new URI(httpMethod.getURI().toString()
							+ "?" + getUrl));
				}
			}

			System.out.println("exeAsyncReq getparams:" + httpMethod.getURI());

			localContext.setAttribute(HttpClientContext.COOKIE_STORE,
					cookieStore);

			hc.execute(httpMethod, localContext, callback);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	protected String getHttpContent(HttpResponse response) {

		HttpEntity entity = response.getEntity();
		String body = null;

		if (entity == null) {
			return null;
		}

		try {

			body = EntityUtils.toString(entity, "utf-8");

		} catch (ParseException e) {

			LOG.warn("the response's content inputstream is corrupt", e);
		} catch (IOException e) {

			LOG.warn("the response's content inputstream is corrupt", e);
		}
		return body;
	}
}


5、使用httpclient,这里只介绍了异步的用法

 

 

package com.studyproject.httpclient;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.message.BasicNameValuePair;

/**
 * http client 使用
 * */
public class HttClientUseDemo extends HttpClientService {

	public static void main(String[] args) {

		new HttClientUseDemo().getConfCall();
	}

	public void getConfCall() {

		String url = "http://220.181.14.110/xxxxx/xxxxx/searchbyappid.do";

		List<BasicNameValuePair> urlParams = new ArrayList<BasicNameValuePair>();
		urlParams.add(new BasicNameValuePair("appid", "2"));
		exeHttpReq(url, false, urlParams, null, new GetConfCall());
	}

	public void exeHttpReq(String baseUrl, boolean isPost,
			List<BasicNameValuePair> urlParams,
			List<BasicNameValuePair> postBody,
			FutureCallback<HttpResponse> callback) {

		try {
			System.out.println("enter exeAsyncReq");
			exeAsyncReq(baseUrl, isPost, urlParams, postBody, callback);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 被回调的对象,给异步的httpclient使用
	 * 
	 * */
	class GetConfCall implements FutureCallback<HttpResponse> {

		/**
		 * 请求完成后调用该函数
		 */
		@Override
		public void completed(HttpResponse response) {

			System.out.println(response.getStatusLine().getStatusCode());
			System.out.println(getHttpContent(response));

			HttpClientUtils.closeQuietly(response);

		}

		/**
		 * 请求取消后调用该函数
		 */
		@Override
		public void cancelled() {

		}

		/**
		 * 请求失败后调用该函数
		 */
		@Override
		public void failed(Exception e) {

		}

	}
} 

上述代码中的有些参数,在使用的过程中需要替换。

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

异步的AsyncHttpClient使用详解 的相关文章

随机推荐

  • arduino+esp8266+onenet+mqtt_4G模块(EC20)连接MQTT服务器(EMQ X)

    上面的示意图也是这篇推文的主题 使用三个客户端EC20 ESP8266 MQTTX通过MQTT协议连接上我们搭建的EMQ X服务器最后完成消息的发布和订阅 概述 其中ESP826大家都有认识 那么相对陌生的EC20是一个4G模块 MQTTX
  • vika+obsidian快速进入一个研究领域

    目的是快速熟悉一个陌生的研究领域 写出文献综述 步骤 检索相关文献100篇以上 在vika中建表格 表头如下所示 阅读100篇论文的题目 关键词 摘要 填充vika表格 并找出需要精度的文献10篇左右 中文综述优先 精度10篇论文 并用ob
  • 《程序员面试宝典》第6章 宏和const

    一 用一个宏定义FIND求一个结构体struc里某个变量相对struc的偏移量 int a char b 20 double cc FIND student a 0 FIND student b 4 FIND student cc 4 20
  • vscode 如何自动补全react和jsx代码?

    补全react代码 文件 首选项 设置 打开之后 搜索emmet includeLanguages 添加javascript javascriptreact属性 重启即可生效 补全jsx代码 在原来的搜索位置 搜索emmet trigger
  • 《游戏测试精通》观后感

    第I部分 游戏测试简介 第一章 游戏测试的两条原则 1 不要恐慌 2 不要相信任何人 在第一章第一节的学习中 我了解到了 作为一名测试工作者 不论是不是新手还是一个资深的 老人 在处于以下场景时 都会或多或少的出现恐慌的情况 不熟悉环境或业
  • PCI-E

    PCI E 1 简介 PCI E PCI Express的所写 是最新的总线和接口标准 它原来的名称为 3GIO 是由英特尔提出的 很明显英特尔的意思是它代表着下一代I O接口标准 交由PCI SIG PCI特殊兴趣组织 认证发布后才改名为
  • 1. 两数之和 C++

    给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 但是 数组中同一个元素在答案里不能重复出现 你可以按任意顺
  • 一文搞懂OC门、OD门及其作用

    我们先给出OC门 OD门的定义 然后从原理出发 介绍OC门 OD门的作用 1 什么是OC门 OD门 OC门 Open Collector Gate 集电极开路门 如图1所示 当N1导通时 输出低电平 当N1截止时 输出高阻态 电路的一种输出
  • 火狐安装网页视频下载插件(Video DownloadHelper)

    Video DownloadHelper是一款以最简单的方式下载网页视频的chrome插件 基本上火狐浏览器能够加载出视频流并正常播放的视频该插件都能够抓取 可以说该插件对于网页视频下载还是十分快捷并且使用场景广泛的 本地安装后的版本 Vi
  • 字节数组的妙用

    在计算机高级语言中 字节属于最小单位 例如在Java中 int占用4个字节 long占用8个字节等 基本上所有基本类型 包括String 都可以转换成字节 那么这到底有何作用 本篇博客主要是记录了我使用字节数组的经验 希望可以给大家提供一些
  • volatile详解(任何人都能懂的那种)

    volatile 看了好多篇博客终于明白这个关键字到底是干嘛的 让我综合所有的博客写一篇大家都能理解它的博客 要点赞呦 volatile是一个类型修饰符 作用是作为指令关键字 一般都是和const对应 确保本条指令不会被编译器的优化而忽略
  • 怎么将将 Python 的安装目录添加到了系统的环境变量路径中

    要在 Windows 系统中将 Python 的安装目录添加到环境变量路径中 请按照以下步骤操作 1 打开 控制面板 2 选择 系统和安全 3 选择 系统 4 在 系统属性 中 选择 高级系统设置 5 在 高级 选项卡中 选择 环境变量 6
  • 【微信小程序】微信小程序支付功能实现

    1 前言 微信小程序支付 开启新一代便捷支付新时代 随着互联网技术的不断发展 微信小程序支付已经成为了人们日常生活中不可或缺的一部分 微信小程序是一种无需下载安装即可使用的应用 用户可以通过微信扫描或搜索关键词来打开并使用 而微信小程序支付
  • javascript面试题--持续更新

    前端HTML篇 前端CSS篇 Vue篇 TypeScript篇 React篇 微信小程序篇 前端面试题汇总大全 含答案超详细 HTML JS CSS汇总篇 持续更新 前端面试题汇总大全二 含答案超详细 Vue TypeScript Reac
  • pytorch量化库使用(2)

    FX Graph Mode量化模式 训练后量化有多种量化类型 仅权重 动态和静态 配置通过qconfig mapping prepare fx函数的参数 完成 FXPTQ API 示例 import torch from torch ao
  • 高可用系统的设计与维护

    author skate time 2011 02 11 高可用系统的设计与维护 对于一个高可用的系统评价 主要体现在架构 功能 性能 安全 维护 兼容性等方面 如何设计维护这样一个高可用系统的 1 一个提供7 24服务的网站架构系统 要避
  • mysql主从 读写_mysql主从-读写分离

    一个完整的MySQL读写分离环境包括以下几个部分 应用程序client database proxy database集群 在本次实战中 应用程序client基于c3p0连接后端的database proxy database proxy负
  • 最新RAD Studio 11.3亚历山大版本上市

    By Marco Cantu February 27 2023 Embarcadero很高兴地宣布RAD Studio 11 Alexandria Release 3的发布 也被称为RAD Studio 11 3 同时发布的还有Delphi
  • k8s集群PHP环境使用

    一 环境介绍 k8s版本 1 15 2 存储 阿里云NAS 测试代码 wordpress 二 下载wordpress和创建好数据库等 1 下载wordpress wget https cn wordpress org latest zh C
  • 异步的AsyncHttpClient使用详解

    背景 前面的一篇文章 同步的HttpClient使用详解 中 提到了服务端通进行网络请求的方式 也讲述了在并发量大的情况下使用HttpClient的连接池来提高性能 此方法虽然很有效果 但是当访问量极大或网络不好的情况下也会出现某些网络请求