并发-Executor框架笔记
Executor框架
jdk5开始,把工作单元与执行机制分离开来,工作单元包括Runable和Callable,执行机制由Executor框架来提供。
Executor框架简介
Executor框架的两级调度模型
- Java线程被一对一映射为本地操作系统线程
- java线程启动会创建一个本地操作系统线程
- java线程终止操作系统线程也会被回收
- 操作系统会调度所有线程并将它们分配给可用的cpu
- 在上层,java多线程程序通常把应用分解为若干任务,然后使用用户级调度器将这些任务映射为固定数量的线程。在底层,操作系统内核将这些线程映射到硬件处理器上
- 应用通过Executor框架控制上层调度,下层由操作系统内核控制,下层调度不受应用程序控制。
Executor框架的结构与成员
Executor框架结构
-
主要由任务,任务执行和异步计算结果组成
- 任务:包括被执行任务需要实现的接口:Runnable和Callable
- 任务的执行:包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorServie接口。(ThreadPoolExecutor和ScheduledThreadPoolExecutor两个关键类实现了)
- 异步计算的结果:包括接口Future和实现Future接口的FutureTask类
-
类和接口
-
- Executor是一个接口,是Executor框架的基础,将任务的提交与任务的执行分离开来
- ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务
- ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。比Timer更灵活,功能更强大。
- Future接口和实现Future接口的FutureTask类,代表异步计算的结果
- Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行
-
使用:
- 主线程创建实现Runnable或Callable接口的任务对象,工具类Executors可以把一个Runnable对象封装为一个Callable对象(Executors.callable(Runnable task)或Executors.callable(Runnable task,Object result))
- 可以把Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command)),或者吧Runnable对象或Callable对象提交给ExecutorService执行(ExecutorService.submit(Runnable task)或ExecutorService.submit(Callable task))
- 执行ExecutorService.submit(…),将会返回一个实现Future接口的对象,也可以创建FutureTask然后直接交给ExecutorService执行
- 主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel来取消此任务
Executor框架的成员
-
ThreadPoolExecutor:通常使用工厂类Executors创建
-
FixedThreadPool:创建固定线程数的FixedThreadPool
-
适用于为了满足资源管理的需求,需要限制当前线程数量的应用场景,适用于负载比较重的服务器
-
public static ExecutorService newFixedThreadPool(int nThreads) public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
-
-
SingleThreadExecutor:创建单个线程
-
适用于需要保证顺序地执行各个任务,并且在任意时间点,不会有多个线程是活动的应用场景
public static ExecutorService newSingleThreadExecutor() public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
-
-
CachedThreadPool:创建一个会根据需要创建新线程
-
大小无界的线程池,适用于执行很多短期异步任务的小程序,或负载教轻的服务器
-
public static ExecutorService newCachedThreadPool() public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
-
-
-
ScheduledThreadPoolExecutor:通常使用工厂类Executors创建
-
创建ScheduledThreadPoolExecutor:包含若干线程的ScheduledThreadPoolExecutor
-
适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求需要限制后台线程数量的应用场景
-
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
-
-
创建SingleThreadScheduledExecutor:包含一个线程的ScheduledThreadPoolExecutor
-
适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景
-
public static ScheduledExecutorService newSingleThreadScheduledExecutor(int corePoolSize) public static ScheduledExecutorService newSingleThreadScheduledExecutor(int corePoolSize, ThreadFactory threadFactory)
-
-
-
Future接口
-
Future接口和Future接口的FutureTask类用来表示异步计算的结果
-
把Runnable接口或Callable接口的实现类提交给ThreadPoolExecutors或ScheduledThreadPoolExecutors时,会返回给一个FutureTask对象
-
<T> Future<T> submit(Callable<T> task) <T> Future<T> submit(Runnable task, T result) Future<> submit(Runnable task)
-
-
Runnable接口和Callable接口
-
Runnable不会返回结果,Callable会返回结果
-
可以把Runnable包装成Callable
-
public static Callable<Object> callable(Runnable task)
-
可以把Runnable和一个待返回的结果包装成一个Callable
-
public static <T> Callable<T> callable(Runnable task, T result)
-
把callable对象提交给执行时,submit会返回一个FutureTask对象
- 执行get方法等待任务执行完成,任务执行完成后get方法将返回该任务的结果
-
ThreadPoolExecutor详解
构成组件
- corePool:核心线程池大小
- maximumPool:最大线程池大小
- BlockingQueue:用来暂时保存任务的工作队列
- RejectedExecutionHandler:当ThreadPoolExecutor已经关闭或者饱和时,execute方法将要调用的Handler
创建类型
- FixedThreadPool
- SingleThreadExecutor
- CachedThreadPool
FixedThreadPool详解
固定线程数线程池
public static ExecutorService newFixedThreadPool(int nThreads){return new ThreadPoolExecutor(nThreads,nThreads, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
}
- corePoolSize 和maximumPoolSize都被设置为创建FixedThreadPool时指定的参数
- 当啊线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的最长时间,超过这个时间后多余的线程将被终止
- keepAliveTime设置为0,多余空闲线程会被立即终止
流程
- 如果当前运行线程数少于corePoolSize,则创建新线程来执行任务
- 在线程池完成预热后(当前运行的线程数等于corePoolSize),将任务加入LinkedBlockingQueue
- 线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue获取任务执行
- 使用无界队列LinkedBlockingQueue作为线程池工作队列,使用无界队列作为工作队列会对线程池带来影响
- 当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中的线程数不会超过corePoolSize
- 由于上条,使用无界队列时,maximumPoolSize将是一个无效参数
- 由于上条和上上条,使用无界队列时keepAliveTIme将是一个无效参数
- 由于使用无界队列,运行中的FixedThreadPool不会拒绝任务
SingleThreadExecutor详解
使用单个worker线程的Executor
public static ExecutorService newSingleThreadExecutor(){return new ThreadPoolExecutor(1,1, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
}
- corePoolSize 和maximumPoolSize都被设置为1
- keepAliveTime设置为0,多余空闲线程会被立即终止
- 使用无界队列LinkedBlockingQueue作为线程池的工作队列
工作流程
- 如果当前运行的线程数少于corePoolSize,则创建一个新线程来执行任务
- 在线程池完成预热后,将任务加入LinkedBlockingQueue
- 线程执行完1中的任务后,会在一个无限循环中反复从LinkedBlockingQueue获取任务来执行
CachedThreadPool详解
根据需要创建新线程的线程池
public static ExecutorService newCachedThreadPool(int nThreads){return new ThreadPoolExecutor(0,Integer.MAX_VALUE, 60L,TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>())
}
- corePoolSize设置为0
- maximumPoolSize被设置为Integer.MAX_VALUE
- keepAliveTime设置为60L,线程池中的空闲线程等待新任务的最长时间是60秒,空闲线程超过60秒将会被终止
- 使用没有容量的SynchronousQueue作为线程池的工作队列
- 如果主线程提交的任务速度高于maximumPool中线程处理任务的速度时,CachedThreadPool会不断创建新线程,极端情况下,会因为创建过多线程为耗尽cpu和内存资源
流程:
- 首先执行SynchronousQueue.offer(Runnable task)。如果当前maximumPool中有空闲线程正则执行SynchronousQueue.poll,那么主线程执行offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行,execute()方法执行完成;否则执行步骤2
- 当初始maximumPool为空,或者maximumPool中当前没有空闲线程时,将没有线程执行SynchronousQueue.poll.这种情况下,步骤1 将失败,此时CachedThreadPool会创建一个新线程执行任务,execute方法执行完成
- 在步骤2中新创建将任务执行完后,会执行SynchronousQueue.poll,这个poll操作会让空闲线程最多在SynchronousQueue中等待60s,如果60s内主线程提交了一个新任务,那么这个空闲线程将执行主线程提交的新任务,否则这个空闲线程将终止。由于空闲60秒的空闲线程会被终止,因此长时间保持空闲的CachedThreadPool不会使用任何资源。
ScheduledThreadPoolExecutor详解
- 继承自ThreadPoolExecutor
- 主要用来在给定的延迟之后运行任务,会定期执行任务。
- 可以在构造函数中指定多个对应的后台线程数
ScheduledThreadPoolExecutor运行机制
- DelayQueue是一个无界队列。
主要两部分
- 当调用ScheduledThreadPoolExecutor的scheduleAtFixedRate方法或者scheduleWithFixedDelay方法时,会向ScheduledThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduledFuture接口的ScheduledFutureTask
- 线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务。
ScheduledThreadPoolExecutor为了实现周期性的执行任务,对ThreadPoolExecutor做了如下修改
- 使用DelayQueue作为任务队列
- 获取任务的方式不同
- 执行周期任务后,增加了额外的处理
ScheduledThreadPoolExecutor的实现
ScheduledFutureTask成员变量:
- long time:表示这个任务将要被执行的具体时间
- long sequenceNumber:表示这个任务被添加到ScheduledThreadPoolExecutor中的序号
- long period:表示任务执行的间隔周期
DelayQueue封装了一个优先级队列,这个优先级队列会将队列的任务根据time排列,小的在前,如果time相同,比较sequenceNumber,小的在前
ScheduledThreadPoolExecutor执行某个周期任务步骤
- 线程从DelayQueue中获取已到期的ScheduledFutureTask,到期任务是指ScheduledFutureTask的time大于等于当前时间
- 获取Lock
- 获取周期任务
- 如果PriorityQueue为空,当前线程到Condition中等待
- 如果PriorityQueue的头元素的time时间比当前时间大,到condition中等待到time时间
- 获取PriorityQueue的头元素,如果不为空,则唤醒condition中等待的所有线程
- 释放Lock
- 线程执行ScheduledFutureTask
- 线程修改ScheduledFutureTask的time后边变为下次将要被执行的时间
- 线程把这个修改time之后的ScheduledFutureTask放回到DelayQueue中
- 获取Lock
- 添加任务
- 向PriorityQueue添加任务
- 如果添加的任务是头元素,唤醒Condition中等待的所有线程
- 释放Lock
FutureTask详解
Future接口和实现Future接口的FutureTask类,代表异步计算的结果
简介
- FutureTask除了实现Future接口外,还实现了Runnable接口。
- FutureTask可以交给Executor执行,也可以由调用线程直接执行
- FutureTask可以处于3种状态
- 未启动:run方法还没有被执行前
- 执行FutureTask.get将导致调用线程阻塞
- 执行FutureTask.cancel将导致此任务永远不会被执行
- 已启动:run方法被执行过程中
- 执行FutureTask.get将导致调用线程阻塞
- 执行FutureTask.cancel(true)将以中断执行此任务线程的方式来试图停止任务
- 执行FutureTask.cancel(false)将不会对正在执行此任务的线程产生影响
- 已完成:run方法执行完后正常结束,或被取消,或执行run方法时抛出异常而异常结束
- 执行FutureTask.get将导致调用线程立即返回结果或抛出异常
- 执行FutureTask.cancel()返回false
- 未启动:run方法还没有被执行前
使用
- 可以把FutureTask交给Executor执行
- 可以通过ExecutorService.submit返回一个FutureTask,然后执行FutureTask.get或cancel方法
- 也可以单独使用FutureTask
当一个线程需要等待另一个线程把某个任务执行完后才能执行,此时可以使用FutureTask
实现
-
基于AQS实现,包含两种类型操作
- 至少一个acquire操作,阻塞调用线程,除非直到AQS状态允许这线程继续执行,FutureTask的acquire操作为get方法调用
- 至少一个release操作,这个操作改变AQS的状态,改变后的状态可以允许一个或多个阻塞线程被解除阻塞,FutureTask的release操作包括run和cancel
-
Sync是FutureTask的内部私有类,继承自AQS,FutureTask的所有公有方法都直接委托给了内部私有Sync
-
FutureTask.get方法会用AQS的acquireSharedInterruptibly方法,执行过程
- 调用AQS的acquireSharedInterryptibly方法,
- 回调在子类Sync中实现的tryAcquireShared()方法来判断acquire操作是否可以成功
- 成功条件:state为执行完成状态RAN或已取消状态CANCELLED,且runner不为null
- 回调在子类Sync中实现的tryAcquireShared()方法来判断acquire操作是否可以成功
- 如果成功则get方法立即返回,如果失败则到线程等待队列中去等待其他线程执行release操作
- 当其他线程执行release操作唤醒当前线程后,当前线程再次执行tryAcquireShared()将返回正值1,当前线程将离开线程等待队列并唤醒它的后继线程
- 最后返回计算的结果或抛出异常
FutureTask.run方法
- 执行在构造函数中指定的任务(Callable.call)
- 以原子方式来更新同步,如果这个原则操作成功,就设置代表计算结果的变量result的值为callable.call的返回值,然后调用AQS.releaseShared
- AQS.releaseShared首先会回调在子类Sync中实现的tryReleaseShared来执行release操作,AQS.releaseShared,然后唤醒线程等待队列中的第一个线程
- 调用FutureTask.done1
- 调用AQS的acquireSharedInterryptibly方法,
相关文章:
并发-Executor框架笔记
Executor框架 jdk5开始,把工作单元与执行机制分离开来,工作单元包括Runable和Callable,执行机制由Executor框架来提供。 Executor框架简介 Executor框架的两级调度模型 Java线程被一对一映射为本地操作系统线程 java线程启动会创建一个本…...
【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)
前言: 本文是对于动态内存管理知识后续的补充,以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser~的博客-CSDN博客 本文涉及的知识内容主要在两方面: 简单解析C/C程序…...
深入理解 JVM 之——字节码指令与执行引擎
更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 类文件结构 Write Once,Run Anywhere 对于 C 语言从程序到运行需要经过编译的过程,只有经历了编译后,我们所编写的代码才能够翻译为机器可以直接运行的二进制代码&#x…...
C++:vector
目录 一、关于vector 二、vector的相关函数 三、相关函数的使用 ①构造函数 ②size ③[] 编辑 ④push_back ⑤迭代器iterator ⑥reserve ⑦resize ⑧find ⑨insert ⑩erase ⑪sort 一、关于vector vector比较像数组 观察可知,vector有两个模板参数…...
Android Automotive编译
系统准备 安装系统 准备一台安装Ubuntu系统的机器(windows系统的机器可以通过WSL安装ubuntu系统) 安装docker 本文使用docker进行编译,因此提前安装docker。参考网络链接安装docker并设置为不使用sudo进行docker操作。 参考链接ÿ…...
什么是50ETF期权开户条件,怎么开期权交易权限?
50ETF期权是指上证50ETF期权,标的物是上证50ETF,代码是(510500),期权是一种在上证50ETF基础上进行衍生品交易的金融工具,下文科普什么是50ETF期权开户条件,怎么开期权交易权限?本文来…...
React 从入门到精通——本文来自AI创作助手
React是一个流行的JavaScript库,用于构建用户界面。以下是React入门到精通的步骤: 入门 安装React 你可以在npm上下载React包,也可以使用其他包管理器。首先需要安装node.js,然后使用以下命令安装React: npm insta…...
【51单片机实验笔记】前篇(三) 模块功能封装汇总(持续更新)
文章目录 通用函数public.hpublic.c 延时函数delay.hdelay.c LED模块数码管模块smg.hsmg.c LED点阵模块独立按键模块矩阵按键模块外部中断模块定时器模块串口通讯模块ADC模块PWM模块 通用函数 包含常用头文件,宏定义,自定义类型,函数工具等。…...
Excel VSTO开发4 -其他事件
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 4 其他事件 针对插件的事件主要有Startup、Shutdown这两个事件,在第2节中已经讲解。在开发窗口中,选择对象…...
语音识别数据的采集方法:基本流程数据类型
“人工智能是一种模仿人类功能的产品。数据采集的方法需要针对特定的场景需求。”—–Mark Brayan (澳鹏CEO) 我们一直说,对于一个高质量的人工智能产品离不开高质量的训练数据。对于不同的人工智能我们需要不同的数据对其训练。要采集正确的数据去训练特定的模型才…...
oracle数据库给用户授权DBA权限Oracle查看哪些用户具有DBA权限
oracle数据库给用户授权DBA权限 步骤一:以sysdba身份登录到Oracle数据库 在授予DBA权限之前,我们首先要以sysdba身份登录到Oracle数据库。使用以下命令登录: sqlplus / as sysdba步骤二:创建用户(如有用户跳过&#…...
024-从零搭建微服务-系统服务(六)
写在最前 如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 源码地址(后端):https://gitee.com/csps/mingyue 源码地址(前端):https://gitee.com/csps…...
Arduino驱动TCS3200传感器(颜色传感器篇)
目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 TCS3200颜色传感器是一款全彩的颜色检测器,包括了一块TAOS TCS3200RGB感应芯片和4个白色LED灯,TCS3200能在一定的范围内检测和测量几乎所有的可见光。TCS3200有大量的光检测器,每个都有红绿蓝和清…...
基于Matlab实现多个数字水印案例(附上源码+数据集)
数字水印是一种在数字图像或视频中嵌入特定信息的技术,以保护知识产权和防止盗版。在本文中,我们将介绍如何使用Matlab实现数字水印。 文章目录 实现步骤源码数据集下载 实现步骤 首先,我们需要选择一个用于嵌入水印的图像。这可以是原始图像…...
C语言之指针进阶篇(2)
目录 函数指针 函数名和&函数名 函数指针的定义 函数指针的使用 函数指针陷阱 代码1 代码2 注意 函数指针数组定义 函数指针数组的使用 指向函数指针数组的指针 书写 终于军训圆满结束了,首先回顾一下指针进阶篇(1)主要是…...
C++ 进制转化入门知识(1)
一、什么是进制 进制是一种用来表示数值的系统或方法,它是基于一个特定的基数来工作的。在我们常见的几种进制中,有: 1. **二进制(基数 2)**: 二进制只用两个数字:0和1。这是计算机内部使用…...
【React】React学习:从初级到高级(四)
React学习[四] 4 应急方案4.1 使用ref引用值4.1.1 给组件添加ref4.1.2 ref和state的不同之处4.1.3 何时使用ref 4.2 使用ref操作DOM4.2.1 获取指向节点的ref4.2.3 使用 ref 回调管理 ref 列表4.2.4 访问另一个组件的DOM节点4.2.5 用 flushSync 同步更新 state 4.3 使用Effect同…...
微信小程序登录问题(思路简略笔记)
配置问题 这是小程序登录问题,必要的两个配置。 流程思路 1. 微信小程序端,会返回一个code。 2. 查看需要返回给微信小程序端的数据。 3. 既然需要返回三个数据,先看openid如何拿到 WX-Login https://api.weixin.qq.com/sns/jscode2ses…...
Go 锁扩展
文章目录 TryLock统计 goroutine数量读写锁读锁写锁常见死锁情况写锁重入写锁中调用读锁循环依赖 TryLock 源码中自带的(我的go是 1.20版本)TryLock 会尝试获取锁,如果获取不到返回false,并不会进行休眠阻塞(和 Lock的主要区别) func (m *Mutex) TryLo…...
Docker的简介及安装
[shouce]http://shouce.jb51.net/docker_practice/栾一峰菜鸟教程参考文献 1 环境配置的难题 软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境都不相同,你怎么知道自家的软件,能在那些机器跑起来? 用户必须保证两件事…...
安卓核心板的不同核心规格及架构介绍
安卓核心板是将核心功能封装的一块电子主板,集成芯片、存储器和功放器件等,并提供标准接口的芯片。 其特点: ● 能跑 Android 等操作系统 强大的功能及丰富的接口 支持 LCD/TP,Audio,Camera,Video&#…...
flume1.11.0安装部署
1、准备安装包apache-flume-1.11.0-bin.tar.gz; 上传; 2、安装flume-1.11.0; 解压; tar -zxvf apache-flume-1.11.0-bin.tar.gz -C /opt/server 进入conf目录,修改flume-env.sh,配置JAVA_HOME;…...
通过wordpress 自定义主题的额外CSS删除指定区块
最近用wordpress建站,想要删除指定区块,发现相关的教程蛮少的,作为小白的我搜了相关教程,好像没找到,只能自己慢慢摸索了,看了很多,终于尝试实现了,特记录下,免得自己忘了…...
Rokid Jungle--Max pro
介绍和功能开发 YodaOS-Master操作系统:以交换计算为核心,实现单目SLAM空间交互,具有高精度、实时性和稳定性。发布UXR2.0SDK,为构建空间内容提供丰富的开发套件 多模态交互 算法原子化 多种开发工具协同 多生态支持 骁龙XR2…...
【LeetCode算法系列题解】第61~65题
CONTENTS LeetCode 61. 旋转链表(中等)LeetCode 62. 不同路径(中等)LeetCode 63. 不同路径 II(中等)LeetCode 64. 最小路径和(中等)LeetCode 65. 有效数字(困难ÿ…...
MATLAB中fillmissing函数用法
目录 语法 说明 示例 包含 NaN 值的向量 由 NaN 值组成的矩阵 插入缺失数据 使用移动中位数方法 使用自定义填充方法 包含缺失端点的矩阵 包含多个数据类型的表 fillmissing函数的功能是填充缺失的条目。 语法 F fillmissing(A,constant,v) F fillmissing(A,meth…...
电脑同时连接有线和无线网络怎么设置网络的优先级
电脑同时连接有线和无线网络怎么设置网络的优先级: 我们知道在 笔记本电脑系统 中,可以通过有线或无线网络进行联网。如果电脑在有线网络和无线网络同时存在的情况,应该怎么设置有线网络优先连接呢?对此我们提供下面的方法可以让电脑在有Wi…...
el-form表单动态校验(场景: 输入框根据单选项来动态校验表单 没有选中的选项就不用校验)
el-form表单动态校验 el-form常规校验方式: // 结构部分 <el-form ref"form" :model"form" :rules"rules"><el-form-item label"活动名称: " prop"name" required><el-input v-model"form.name" /…...
Java 数据结构与算法应该如何学习?
学习数据结构是计算机科学和软件工程领域中的重要基础知识之一。掌握数据结构对于编写高效、可扩展和可维护的代码至关重要。 1、掌握基本概念 首先,你需要掌握数据结构的基本概念。了解不同类型的数据结构,如数组、链表、栈、队列、树、图等ÿ…...
力扣(LeetCode)算法_C++——有效的数独
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) …...
网站建设 工作建议/广州专做优化的科技公司
原创;微信公众号:千里行走;受限图片大小限制,有些图片不是很清晰,可以到微信公众号查看;目录(1).前述(2).nginx生产级别高性能配置正文(1).前述笔者在github提供了完整的配置文件,同时包含代理基…...
一键查询注册过的网站/网络推广都有哪些方式
一、用 python 进行微信好友分析 1、使用到的库 (1)wxpy:初始化微信机器人 (2)openpyxl:保存微信好友数据为Excel表格 (3) pyecharts:生成可视化的地图 (4&am…...
网站建设策划书提纲/海外推广渠道
本文档主要讲解在迅为iTOP-iMX6Q/D/PLUS 开发板的设备树内核(4.1.15)源码中,设备树注册 驱动和非设备树的类似。 1 注册驱动源码分析 设备树的内核驱动中,platform_driver 结构中增加了“of_match_table”,在驱动源码 …...
网站互动怎么做/网站被禁用如何解决
akuna的电面题 脑子晕了没想出标算/// Permutation: all possible result of permute a list of numbers , for example [1,3,5] → [1,3,5],[1,5,3],[3,5,1],[3,1,5],[5,1,3],[5,3,1] /// [1,1,5] -> [1,5,1], [5,1,1], [1,1,5] 可用置换的方式,从小往大推&…...
成都奶茶加盟网站建设/免费推广的方式
编码成分子的信号传输(如激素、信息素)是人体用于确保细胞间通信的常用系统之一,在体外通过分子通信(MC)领域模拟了一种信息传输形式。然而,在实验室中复制MC仍然面临着许多挑战,例如MC中可以同时编码、传输和解码的化学载体数量的限制。该项…...
重庆快速网站建设/百度图片搜索图片识别
jQuery之事件移除 转载于 https://www.cnblogs.com/jiqing9006/archive/2012/09/12/2681323.html有时候事件执行完了,想取消事件的效果可以通过一定的办法来处理。比如bind()方法,可以通过unbind()方法来移除事件的效果。 比如下面的一个案例࿱…...