线程池

C++ 服务端 性能优化

柔情痞子 提交于 2020-03-01 13:08:23
编写正常运行的程序很容易,但一旦数据量大起来,对代码的性能就需要认真考虑了。对于服务器来说,如果客户端一次访问,就需要话费几百毫秒,那么一旦每秒的访问次数多起来,后续的请求就会造成很明显的延迟。严重影响用户体验。最近做后端服务也遇到了一些需要优化的问题,数据量大了后,有明显延迟。 性能优化的前提是良好的构架设计:如果架构本身的设计就存在问题,在怎么优化也所能提升的空间也是很小。根据二八原则,大部分性能应该消耗在很少的地方,所以优化的关注点就在于那20%最耗时的代码块,解决了这个问题,整体性能就会有很大的提升。 代码层面的优化一般涉及到一下方面: ##1.并发模型的选择 对于不同的功能需要用不同的并发模型,适合单线程还是多线程,以及线程池这些都会影响到性能,对于服务器,模块是io密集型还是计算密集型。例如如果一次请求是需要做很多的计算,那么用线程池是合理的能够简化编程,但是如果一次请求主要时间是等待io,那么线程池是无法提升吞吐量的。 ##2.数据的存储 ###容器的选择 数据对象的存储方式取决于对数据的使用方式,就拿C++容器来说,如果要存储物品信息,一般系统中更多的是根据物品id来获取物品信息,那么久需要用key-value来存取,但map是红黑树,unorder_map是哈希表,哈希表的查询时间是O(1),而对于map,插入、删除都是O(logN),最坏和平均都是。 ##

多线程(二)

白昼怎懂夜的黑 提交于 2020-03-01 12:48:17
使用线程池 Java语言虽然内置了多线程支持,启动一个新线程非常方便,但是,创建线程需要操作系统资源(线程资源,栈空间等),频繁创建和销毁大量线程需要消耗大量时间。 而线程池内部维护了若干个线程,没有任务的时候,这些线程都处于等待状态。如果有新任务,就分配一个空闲线程执行。如果所有线程都处于忙碌状态,新任务要么放入队列等待,要么增加一个新线程进行处理。 一、线程池实现 FixedThreadPool: 线程数固定的线程池 // 创建一个固定大小的线程池: ExecutorService es = Executors . newFixedThreadPool ( 4 ) ; CachedThreadPool: 线程数根据任务动态调整的线程池 SingleThreadExecutor: 仅单线程执行的线程池 创建指定动态范围的线程池: //最大10,最少4 int min = 4 ; int max = 10 ; ExecutorService es = new ThreadPoolExecutor ( min , max , 60 L , TimeUnit . SECONDS , new SynchronousQueue < Runnable > ( ) ) ; 创建反复指定任务的线程池: ScheduledExecutorService ses = Executors .

如何计算tomcat线程池大小?

拟墨画扇 提交于 2020-03-01 12:07:22
背景   在我们的日常开发中都涉及到使用tomcat做为服务器,但是我们该设置多大的线程池呢?以及根据什么原则来设计这个线程池呢?   接下来,我将介绍本人是怎么设计以及计算的。 目标   确定tomcat服务器线程池大小 具体方法   众所周知,tomcat接受一个request后处理过程中,会涉及到cpu和IO时间。其中IO等待时,cpu被动放弃执行,其他线程就可以利用这段时间片进行操作。 所以我们可以采用服务器IO优化的通用规则: 线程大小 = ( (线程io时间 + 线程cpu) / 线程cpu time) * cpu核数 举例: 线程io时间为100ms(IO操作比如数据库查询,同步远程调用等),线程cpu时间10ms,服务器物理机核数为4个。通过上面的公式,我们计算出来的大小是 ((100 + 10 )/10 ) *4 = 44。理论上我们有依据,但是实际计算过程中我们怎么知道线程IO时间和cpu时间呢? 这个就涉及到实际编码过程中的怎么样监控处理时间啦。 下面我介绍本人项目中的做法   1. 通过java 实现内置的filter接口,我们可以拿到一个request消耗的总时间 public class MoniterFilter implements Filter { private static final Logger logger = LoggerFactory

获得多线程的方式之线程池

百般思念 提交于 2020-03-01 11:57:27
获得多线程的方式之线程池 谈谈你对线程池的理解 什么是线程池?优势? 线程池的主要作用控制运行的线程的数量,简单来说,存放多个线程的池子,用到的时候从池中取线程去执行队列任务,执行完任务线程的释放 主要特点: 线程复用(避免重复方法创建和销毁线程,降低资源消耗,提高了响应速度) 控制并发线程数(可以设置线程的数量) 管理线程(对多个线程进行统一的分配,调优和监控) 优势:降低资源消耗,提高了响应速度,提高线程可控性 线程池怎么使用? 架构说明:Java中的线程池是通过Executor框架实现的,该框架用到了Executor、Executors、ExecutorService、ThreadPoolExecutor 尤其重点注意ThreadPoolExecutor它是线程池的执行类 主要获得线程池的方法: 1)//一池固定数线程(适用于执行长期的任务,好很多) ExecutorService threadPool = Executors.newFixedThreadPool(4);//一池3个处理线程(银行3个处理窗口) 2)//一池一个数线程(适用于一个任务一个任务执行的场景) ExecutorService threadPool = Executors.newSingleThreadExecutor();//一池1个处理线程(银行只有1个处理窗口) 3)//一池N个数线程

asyncTask详解

浪尽此生 提交于 2020-03-01 06:35:54
介绍 android UI是线程不安全的,因此想实现在子线程中刷新UI就需要借助一些机制来实现,一般有两种方法:handler+message;还有一种就是今天我们要讲的asyncTask。asyncTask相对 handler+message 要轻量级一些。 基本用法 asyncTask 是一个抽象类,因此我们需要自定义一个类来继承他,并且实现他的方法。 asyncTask 指定了三个泛型参数,其中Params是可变长的泛型参数,三个参数用法如下: Params: asyncTask 传入的参数可在后台执行任务时使用 Progress:后台执行任务时,如果需要在前台显示进度,这里是指定泛型作为进度单位 Result:后台执行任务完成,如果需要返回结果到前台,这里是指定泛型作为返回值类型 除了参数下面介绍下我们经常需要重写的四个方法: onPreExecute():在任务执行之前调用,进行一些初始化操作,比如显示一个进度条,这个方法是在主线程运行的。 doInBackground(Void... arg0):这个方法是用来执行耗时操作的,把你想要异步处理的任务的代码放在这里面,这个肯定是在子线程执行的。所以这个方法里面不能进行UI操作,如果想要更新UI的话,比如更新进度可以调用publishProgress(values)方法。 onProgressUpdate(Integer..

JAVA线程池ThreadPoolExecutor

纵然是瞬间 提交于 2020-02-29 20:50:20
java.util.concurrent.ThreadPoolExecutor相关基础介绍和使用示例。 [ 一 ]、常用线程池 最常用构造方法为: ThreadPoolExecutor(int corePoolSize, JAVA中IP和整数相互转化 int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) JDK自带的配置好的线程池: // 固定工作线程数量的线程池 ExecutorService executorService1 = Executors.newFixedThreadPool(3); // 一个可缓存的线程池 ExecutorService executorService2 = Executors.newCachedThreadPool(); // 单线程化的Executor ExecutorService executorService3 = Executors.newSingleThreadExecutor(); // 支持定时的以及周期性的任务执行 ExecutorService executorService4 = Executors

Executors常用的创建ExecutorService的方法的简单说明

荒凉一梦 提交于 2020-02-29 19:49:04
一、线程池的创建 我们可以通过ThreadPoolExecutor来创建一个线程池。 Java代码 ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) 创建一个线程池需要输入几个参数: corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会 创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创 建并启动所有基本线程。 runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。 ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。 LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

深入浅出NodeJS——异步I/O

一个人想着一个人 提交于 2020-02-29 19:36:50
底层操作系统,异步通过信号量、消息等方式有着广泛的应用。 PHP语言从头到尾都是以同步堵塞方式执行,利于程序猿顺序编写业务逻辑。 异步I/O、事件驱动、单线程构成Node的基调。 why异步I/O (1)、用户体验 在Web2.0中Ajax广泛应用异步刷新机制能够更好的提高用户体验,消除UI堵塞。后端相同採用异步I/O能够有效较少同一时候请求多个资源的效应时间其为max(M,N)。 (2)、资源分配 多任务主流方式: a. 单线程异步I/O b. 多线程并行 多线程的代价在于创建线程和运行期线程上下午切换的开销较大。在复杂场景中,多线程常常面临锁、状态同步的问题。但多线程能够更有效的利用多核CPU,提高利用率。 NodeJS利用单线程远离多线程死锁、状态同步等问题;利用异步I/O,让单线程远离堵塞,以更好利用CPU。 为了弥补单线程无法利用多核CPU特点,Node採用类似Web Workers的子进程。 异步I/O 操作系统内核对于I/O仅仅有两种方式:堵塞和非堵塞 堵塞I/O一个特点是调用之后一定要等到系统内核层面完毕全部操作后,调用才结束。其造成CPU等待I/O,浪费时间和资源,CPU利用不充分。 非堵塞I/O不同之处在于调用之后会马上返回。其问题在于为了获取完整的数据,应用程序须要反复调用I/O操作来确认是否完毕,这样的反复调用判定是否完毕的技术叫做 轮询 堵塞I

java 线程池管理类:Executors

混江龙づ霸主 提交于 2020-02-29 15:41:32
java.util.concurrent 类 Executors java.lang.Object 继承者 java.util.concurrent.Executors 此类是个 工具类 ,它提供对 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的一些实用方法。 此类支持以下 各种方法 : * 创建并返回设置有常用配置的 ExecutorService 的方法。 * 创建并返回设置有常用配置的 ScheduledExecutorService 的方法。 * 创建并返回“包装的” ExecutorService 方法,它使特定于实现的方法不可访问,只让 ExecutorService 接口的方法可用。 * 创建并返回 ThreadFactory 的方法,它可将新创建的线程设置为已知的状态。 * 创建并返回非闭包形式的 Callable 的方法,这样可将其用于需要 Callable 的执行方法中。 主要方法: public static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。 在任意点,在大多数 nThreads 线程会处于处理任务的活动状态

多线程

淺唱寂寞╮ 提交于 2020-02-29 13:46:15
AbortPolicy 该策略是线程池的默认策略。使用该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。 源码如下: public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //不做任何处理,直接抛出异常 throw new RejectedExecutionException("xxx"); } DiscardPolicy 这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。 源码如下: public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //就是一个空的方法 } DiscardOldestPolicy 这个策略从字面上也很好理解,丢弃最老的。也就是说如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。 因为队列是队尾进,队头出,所以队头元素是最老的,因此每次都是移除对头元素后再尝试入队。 源码如下: public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { //移除队头元素 e