当前位置: 首页 > news >正文

Android Glide 框架线程管理模块原理的源码级别深入分析

一、引言

在现代的 Android 应用开发中,图片加载是一个常见且重要的功能。Glide 作为一款广泛使用的图片加载框架,以其高效、灵活和易用的特点受到了开发者的青睐。其中,线程管理模块是 Glide 框架中至关重要的一部分,它负责协调不同线程之间的工作,确保图片的加载、解码、处理等操作能够高效、有序地进行。合理的线程管理可以提高应用的性能,避免主线程阻塞,从而为用户提供流畅的交互体验。

本文将深入 Glide 框架的源码,详细剖析其线程管理模块的原理。从线程池的创建和配置,到不同任务在各个线程之间的调度和执行,每一个步骤都会结合具体的代码进行分析。同时,还会探讨线程管理模块与 Glide 其他模块之间的协作关系,以及如何在实际开发中合理利用线程管理来优化图片加载性能。

二、线程管理模块概述

Glide 的线程管理模块主要负责以下几个方面的工作:

  1. 线程池的创建和管理:Glide 使用多个线程池来处理不同类型的任务,如网络请求、磁盘缓存读写、图片解码等。通过合理配置线程池的参数,可以提高任务的执行效率。
  2. 任务的调度和执行:根据任务的类型和优先级,将任务分配到合适的线程池中执行。同时,处理任务的排队和并发控制,确保系统资源的合理利用。
  3. 线程间的通信和同步:在不同线程之间传递数据和状态信息,保证各个模块之间的协作和数据的一致性。例如,在图片加载完成后,将结果从子线程传递到主线程进行显示。

三、线程池的创建和配置

3.1 线程池的种类

Glide 中主要使用了以下几种线程池:

  1. DiskCacheService:用于处理磁盘缓存的读写操作。磁盘 I/O 操作通常比较耗时,使用单独的线程池可以避免阻塞其他任务。
  2. SourceService:用于处理网络请求和图片解码等操作。这些操作可能会消耗大量的 CPU 和网络资源,使用专门的线程池可以提高处理效率。
  3. AnimationExecutor:用于处理动画相关的任务。动画需要在主线程或特定的线程中执行,以保证动画的流畅性。

3.2 线程池的创建和配置源码分析

3.2.1 DiskCacheService 线程池

DiskCacheService 是一个单线程的线程池,用于处理磁盘缓存的读写操作。以下是其创建和配置的源码:

java

// GlideExecutor 类中创建 DiskCacheService 线程池的方法
private static GlideExecutor newDiskCacheExecutor() {// 线程池的核心线程数为 1,即单线程int corePoolSize = 1;// 线程池的最大线程数也为 1int maximumPoolSize = 1;// 线程空闲时的存活时间为 0 毫秒long keepAliveTime = 0L;// 时间单位为毫秒TimeUnit unit = TimeUnit.MILLISECONDS;// 使用 LinkedBlockingQueue 作为任务队列BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();// 创建一个线程工厂,用于创建线程ThreadFactory threadFactory = new DefaultThreadFactory("disk-cache", Process.THREAD_PRIORITY_BACKGROUND);// 创建一个线程池执行器ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory);// 将线程池执行器包装成 GlideExecutor 对象并返回return new GlideExecutor(executor, /*isShutdownAllowed=*/ true);
}

在上述代码中,newDiskCacheExecutor 方法创建了一个单线程的线程池。核心线程数和最大线程数都设置为 1,确保只有一个线程在处理磁盘缓存的读写操作。使用 LinkedBlockingQueue 作为任务队列,保证任务按顺序执行。线程空闲时的存活时间为 0 毫秒,即线程在空闲时会立即终止。最后,将线程池执行器包装成 GlideExecutor 对象返回。

3.2.2 SourceService 线程池

SourceService 是一个多线程的线程池,用于处理网络请求和图片解码等操作。以下是其创建和配置的源码:

java

// GlideExecutor 类中创建 SourceService 线程池的方法
private static GlideExecutor newSourceExecutor() {// 获取可用的处理器核心数int availableProcessors = Runtime.getRuntime().availableProcessors();// 线程池的核心线程数为可用处理器核心数的一半int corePoolSize = Math.max(1, availableProcessors / 2);// 线程池的最大线程数为可用处理器核心数int maximumPoolSize = availableProcessors;// 线程空闲时的存活时间为 60 秒long keepAliveTime = 60L;// 时间单位为秒TimeUnit unit = TimeUnit.SECONDS;// 使用 SynchronousQueue 作为任务队列BlockingQueue<Runnable> workQueue = new SynchronousQueue<>();// 创建一个线程工厂,用于创建线程ThreadFactory threadFactory = new DefaultThreadFactory("source", Process.THREAD_PRIORITY_BACKGROUND);// 创建一个线程池执行器ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory);// 将线程池执行器包装成 GlideExecutor 对象并返回return new GlideExecutor(executor, /*isShutdownAllowed=*/ true);
}

在上述代码中,newSourceExecutor 方法创建了一个多线程的线程池。核心线程数为可用处理器核心数的一半,最大线程数为可用处理器核心数,这样可以充分利用系统资源。使用 SynchronousQueue 作为任务队列,该队列不存储任务,而是直接将任务交给线程处理,提高了任务的执行效率。线程空闲时的存活时间为 60 秒,当线程空闲超过 60 秒时会被终止。最后,将线程池执行器包装成 GlideExecutor 对象返回。

3.2.3 AnimationExecutor 线程池

AnimationExecutor 用于处理动画相关的任务。以下是其创建和配置的源码:

java

// GlideExecutor 类中创建 AnimationExecutor 线程池的方法
private static GlideExecutor newAnimationExecutor() {// 线程池的核心线程数为 1int corePoolSize = 1;// 线程池的最大线程数为 1int maximumPoolSize = 1;// 线程空闲时的存活时间为 0 毫秒long keepAliveTime = 0L;// 时间单位为毫秒TimeUnit unit = TimeUnit.MILLISECONDS;// 使用 LinkedBlockingQueue 作为任务队列BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();// 创建一个线程工厂,用于创建线程ThreadFactory threadFactory = new DefaultThreadFactory("animation", Process.THREAD_PRIORITY_DISPLAY);// 创建一个线程池执行器ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory);// 将线程池执行器包装成 GlideExecutor 对象并返回return new GlideExecutor(executor, /*isShutdownAllowed=*/ true);
}

在上述代码中,newAnimationExecutor 方法创建了一个单线程的线程池。核心线程数和最大线程数都设置为 1,确保动画任务按顺序执行。使用 LinkedBlockingQueue 作为任务队列,保证任务的顺序性。线程空闲时的存活时间为 0 毫秒,即线程在空闲时会立即终止。最后,将线程池执行器包装成 GlideExecutor 对象返回。

3.3 线程池的获取和使用

在 Glide 中,可以通过 GlideExecutor 类的静态方法获取不同的线程池。以下是获取 DiskCacheService 线程池的示例代码:

java

// 获取 DiskCacheService 线程池
GlideExecutor diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
// 提交一个任务到 DiskCacheService 线程池
diskCacheExecutor.execute(new Runnable() {@Overridepublic void run() {// 执行磁盘缓存的读写操作// ...}
});

通过调用 GlideExecutor 类的 newDiskCacheExecutor 方法可以获取 DiskCacheService 线程池,然后使用 execute 方法提交一个任务到该线程池。其他线程池的获取和使用方式类似。

四、任务的调度和执行

4.1 任务的分类

在 Glide 中,任务主要分为以下几类:

  1. 磁盘缓存读写任务:如从磁盘缓存中读取图片数据或将图片数据写入磁盘缓存。
  2. 网络请求任务:从网络获取图片数据。
  3. 图片解码任务:将图片数据解码为 Bitmap 或其他可显示的格式。
  4. 动画任务:处理图片的动画效果。

4.2 任务调度的源码分析

Glide 通过 EngineJob 类来管理任务的调度和执行。以下是 EngineJob 类中任务调度的部分源码:

java

// EngineJob 类负责管理任务的调度和执行
public class EngineJob<R> implements DecodeJob.Callback<R> {private final GlideExecutor diskCacheExecutor; // 磁盘缓存线程池private final GlideExecutor sourceExecutor; // 源数据线程池private final GlideExecutor animationExecutor; // 动画线程池private DecodeJob<R> decodeJob; // 解码任务public EngineJob(GlideExecutor diskCacheExecutor,GlideExecutor sourceExecutor,GlideExecutor animationExecutor) {this.diskCacheExecutor = diskCacheExecutor;this.sourceExecutor = sourceExecutor;this.animationExecutor = animationExecutor;}// 开始执行任务public void start(DecodeJob<R> decodeJob) {this.decodeJob = decodeJob;// 将解码任务提交到磁盘缓存线程池执行diskCacheExecutor.execute(decodeJob);}@Overridepublic void onResourceDecoded(Resource<R> resource, DataSource dataSource) {// 当资源解码完成后,根据数据源类型选择合适的线程池执行后续任务if (dataSource == DataSource.DATA_DISK_CACHE) {// 如果数据来自磁盘缓存,将任务提交到源数据线程池执行sourceExecutor.execute(new ResourceReadyCallback(resource, dataSource));} else {// 否则,直接在当前线程执行后续任务handleResultOnMainThread(resource, dataSource);}}// 在主线程处理结果private void handleResultOnMainThread(Resource<R> resource, DataSource dataSource) {// ...}// 资源准备好的回调任务private class ResourceReadyCallback implements Runnable {private final Resource<R> resource;private final DataSource dataSource;public ResourceReadyCallback(Resource<R> resource, DataSource dataSource) {this.resource = resource;this.dataSource = dataSource;}@Overridepublic void run() {// 处理资源准备好的逻辑handleResultOnMainThread(resource, dataSource);}}
}

在上述代码中,EngineJob 类包含了三个线程池:diskCacheExecutorsourceExecutoranimationExecutor。在 start 方法中,将解码任务 decodeJob 提交到 diskCacheExecutor 线程池执行。当资源解码完成后,在 onResourceDecoded 方法中,根据数据源类型选择合适的线程池执行后续任务。如果数据来自磁盘缓存,将任务提交到 sourceExecutor 线程池执行;否则,直接在当前线程执行后续任务。

4.3 任务执行的源码分析

任务的执行主要通过 Runnable 接口实现。以 DecodeJob 类为例,以下是其实现 Runnable 接口的部分源码:

java

// DecodeJob 类实现了 Runnable 接口,用于执行解码任务
public class DecodeJob<R> implements Runnable {private final EngineJob<R> engineJob; // 引擎任务private final DataFetcherGenerator generator; // 数据获取生成器public DecodeJob(EngineJob<R> engineJob, DataFetcherGenerator generator) {this.engineJob = engineJob;this.generator = generator;}@Overridepublic void run() {try {// 执行解码任务boolean isResourceDecoded = decodeFromSource();if (isResourceDecoded) {// 如果资源解码成功,通知引擎任务engineJob.onResourceDecoded(resource, dataSource);} else {// 如果资源解码失败,通知引擎任务engineJob.onLoadFailed(new GlideException("Failed to decode resource"));}} catch (Exception e) {// 处理异常情况,通知引擎任务engineJob.onLoadFailed(e);}}// 从源数据解码资源private boolean decodeFromSource() throws Exception {// ...return false;}
}

在上述代码中,DecodeJob 类实现了 Runnable 接口的 run 方法。在 run 方法中,调用 decodeFromSource 方法执行解码任务。如果资源解码成功,调用 engineJobonResourceDecoded 方法通知引擎任务;如果解码失败,调用 engineJobonLoadFailed 方法通知引擎任务。

五、线程间的通信和同步

5.1 线程间通信的方式

在 Glide 中,线程间的通信主要通过以下几种方式实现:

  1. Handler 机制:用于在子线程和主线程之间传递消息。例如,在图片加载完成后,将结果从子线程传递到主线程进行显示。
  2. 回调接口:通过定义回调接口,在不同线程之间传递数据和状态信息。例如,在 DecodeJob 完成解码任务后,通过回调接口通知 EngineJob

5.2 Handler 机制的源码分析

Glide 使用 Handler 机制在子线程和主线程之间传递消息。以下是相关的源码分析:

java

// MainThreadExecutor 类用于在主线程执行任务
public class MainThreadExecutor implements Executor {private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());@Overridepublic void execute(Runnable command) {// 将任务提交到主线程的消息队列中执行MAIN_THREAD_HANDLER.post(command);}
}

在上述代码中,MainThreadExecutor 类实现了 Executor 接口,用于在主线程执行任务。通过 Handlerpost 方法将任务提交到主线程的消息队列中执行。以下是在 EngineJob 类中使用 MainThreadExecutor 的示例代码:

java

// EngineJob 类中在主线程处理结果的方法
private void handleResultOnMainThread(Resource<R> resource, DataSource dataSource) {// 获取主线程执行器MainThreadExecutor mainThreadExecutor = new MainThreadExecutor();// 将任务提交到主线程执行mainThreadExecutor.execute(new Runnable() {@Overridepublic void run() {// 在主线程处理资源结果// ...}});
}

handleResultOnMainThread 方法中,创建了一个 MainThreadExecutor 对象,然后使用 execute 方法将任务提交到主线程执行。

5.3 回调接口的源码分析

回调接口是 Glide 中常用的线程间通信方式。以 DecodeJobEngineJob 之间的通信为例,以下是相关的源码分析:

java

// DecodeJob 类的回调接口
public interface Callback<R> {// 资源解码完成的回调方法void onResourceDecoded(Resource<R> resource, DataSource dataSource);// 加载失败的回调方法void onLoadFailed(GlideException e);
}// DecodeJob 类
public class DecodeJob<R> implements Runnable {private final EngineJob<R> engineJob;public DecodeJob(EngineJob<R> engineJob) {this.engineJob = engineJob;}@Overridepublic void run() {try {// 执行解码任务boolean isResourceDecoded = decodeFromSource();if (isResourceDecoded) {// 如果资源解码成功,通知引擎任务engineJob.onResourceDecoded(resource, dataSource);} else {// 如果资源解码失败,通知引擎任务engineJob.onLoadFailed(new GlideException("Failed to decode resource"));}} catch (Exception e) {// 处理异常情况,通知引擎任务engineJob.onLoadFailed(e);}}
}// EngineJob 类实现了 DecodeJob 的回调接口
public class EngineJob<R> implements DecodeJob.Callback<R> {@Overridepublic void onResourceDecoded(Resource<R> resource, DataSource dataSource) {// 处理资源解码完成的逻辑// ...}@Overridepublic void onLoadFailed(GlideException e) {// 处理加载失败的逻辑// ...}
}

在上述代码中,DecodeJob 类定义了一个回调接口 Callback,包含了 onResourceDecodedonLoadFailed 两个方法。EngineJob 类实现了该回调接口,当 DecodeJob 完成解码任务后,会调用 EngineJob 的相应回调方法,从而实现了线程间的通信。

六、线程管理模块与其他模块的协作

6.1 与缓存模块的协作

线程管理模块与缓存模块密切协作,确保磁盘缓存的读写操作在合适的线程中执行。例如,在 DecodeJob 中,如果需要从磁盘缓存中读取图片数据,会将该任务提交到 DiskCacheService 线程池执行。以下是相关的源码分析:

java

// DecodeJob 类中从磁盘缓存读取数据的方法
private boolean decodeFromCache() {// 创建一个磁盘缓存读取任务DiskCacheGenerator generator = new DiskCacheGenerator(this,diskCache,diskCacheService);// 将任务提交到磁盘缓存线程池执行diskCacheService.execute(generator);return false;
}

在上述代码中,decodeFromCache 方法创建了一个 DiskCacheGenerator 对象,该对象负责从磁盘缓存中读取数据。然后将该任务提交到 diskCacheService 线程池执行。

6.2 与网络模块的协作

线程管理模块与网络模块协作,确保网络请求任务在合适的线程中执行。例如,在 SourceGenerator 中,如果需要从网络获取图片数据,会将该任务提交到 SourceService 线程池执行。以下是相关的源码分析:

java

// SourceGenerator 类中从网络获取数据的方法
private boolean startNext() {// 创建一个网络数据获取器HttpUrlFetcher fetcher = new HttpUrlFetcher(url, timeout);// 将任务提交到源数据线程池执行sourceExecutor.execute(new Runnable() {@Overridepublic void run() {try {// 执行网络请求InputStream inputStream = fetcher.loadData(priority, this);// 处理网络请求结果// ...} catch (IOException e) {// 处理网络请求异常// ...}}});return true;
}

在上述代码中,startNext 方法创建了一个 HttpUrlFetcher 对象,该对象负责从网络获取图片数据。然后将该任务提交到 sourceExecutor 线程池执行。

6.3 与动画模块的协作

线程管理模块与动画模块协作,确保动画任务在合适的线程中执行。例如,在 AnimatableDrawable 中,如果需要执行动画效果,会将该任务提交到 AnimationExecutor 线程池执行。以下是相关的源码分析:

java

// AnimatableDrawable 类中执行动画的方法
public void start() {// 创建一个动画任务AnimationRunnable animationRunnable = new AnimationRunnable(this);// 将任务提交到动画线程池执行animationExecutor.execute(animationRunnable);
}// 动画任务类
private class AnimationRunnable implements Runnable {private final AnimatableDrawable drawable;public AnimationRunnable(AnimatableDrawable drawable) {this.drawable = drawable;}@Overridepublic void run() {// 执行动画逻辑// ...}
}

在上述代码中,start 方法创建了一个 AnimationRunnable 对象,该对象负责执行动画逻辑。然后将该任务提交到 animationExecutor 线程池执行。

七、线程管理模块的性能优化

7.1 合理配置线程池参数

合理配置线程池的参数可以提高任务的执行效率。例如,根据系统的处理器核心数和任务的类型,调整线程池的核心线程数和最大线程数。在 SourceService 线程池中,核心线程数设置为可用处理器核心数的一半,最大线程数设置为可用处理器核心数,这样可以充分利用系统资源。

7.2 任务的优先级管理

Glide 可以通过设置任务的优先级来管理任务的执行顺序。例如,在 Priority 枚举中定义了不同的优先级:

java

// Priority 枚举定义了任务的优先级
public enum Priority {IMMEDIATE, // 立即执行HIGH, // 高优先级NORMAL, // 正常优先级LOW // 低优先级
}

在提交任务时,可以指定任务的优先级,线程池会根据优先级来调度任务。例如:

java

// 提交一个高优先级的任务到源数据线程池
sourceExecutor.execute(new Runnable() {@Overridepublic void run() {// 执行高优先级任务// ...}
}, Priority.HIGH);

7.3 避免线程阻塞

在任务执行过程中,要避免线程阻塞,以免影响其他任务的执行。例如,在进行网络请求时,要使用异步方式进行,避免在主线程中执行耗时的网络操作。Glide 在处理网络请求时,会将网络请求任务提交到 SourceService 线程池执行,避免阻塞主线程。

7.4 线程池的复用和关闭

在使用线程池时,要注意线程池的复用和关闭。避免频繁创建和销毁线程池,以减少系统资源的消耗。同时,在应用退出时,要及时关闭线程池,释放资源。例如,在 Glide 类的 shutdown 方法中,会关闭所有的线程池:

java

// Glide 类的 shutdown 方法
public void shutdown() {// 关闭磁盘缓存线程池diskCacheExecutor.shutdown();// 关闭源数据线程池sourceExecutor.shutdown();// 关闭动画线程池animationExecutor.shutdown();
}

八、线程管理模块的异常处理

8.1 任务执行异常的处理

在任务执行过程中,可能会出现各种异常情况,如网络异常、解码异常等。Glide 在任务执行过程中会捕获这些异常,并进行相应的处理。例如,在 DecodeJob 类的 run 方法中,会捕获异常并通知 EngineJob

java

// DecodeJob 类的 run 方法
@Override
public void run() {try {// 执行解码任务boolean isResourceDecoded = decodeFromSource();if (isResourceDecoded) {// 如果资源解码成功,通知引擎任务engineJob.onResourceDecoded(resource, dataSource);} else {// 如果资源解码失败,通知引擎任务engineJob.onLoadFailed(new GlideException("Failed to decode resource"));}} catch (Exception e) {// 处理异常情况,通知引擎任务engineJob.onLoadFailed(e);}
}

在上述代码中,run 方法捕获了所有异常,并调用 engineJobonLoadFailed 方法通知引擎任务。

8.2 线程池异常的处理

线程池在执行任务时也可能会出现异常,如线程池已满、线程创建失败等。Glide 通过设置线程池的拒绝策略来处理这些异常。例如,在 ThreadPoolExecutor 中,可以设置拒绝策略:

java

// 创建一个线程池执行器,并设置拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,new ThreadPoolExecutor.CallerRunsPolicy() // 使用 CallerRunsPolicy 拒绝策略
);

在上述代码中,使用 CallerRunsPolicy 拒绝策略,当线程池已满时,会将任务返回给调用者线程执行。

九、总结

Glide 的线程管理模块是其高效运行的关键之一。通过合理创建和配置线程池,将不同类型的任务分配到合适的线程池中执行,实现了任务的高效调度和执行。同时,利用线程间的通信和同步机制,确保了各个模块之间的协作和数据的一致性。

线程管理模块与 Glide 的其他模块密切协作,如缓存模块、网络模块和动画模块,共同完成图片的加载、解码和显示等任务。在实际开发中,要合理利用线程管理模块的功能,进行性能优化,

相关文章:

Android Glide 框架线程管理模块原理的源码级别深入分析

一、引言 在现代的 Android 应用开发中&#xff0c;图片加载是一个常见且重要的功能。Glide 作为一款广泛使用的图片加载框架&#xff0c;以其高效、灵活和易用的特点受到了开发者的青睐。其中&#xff0c;线程管理模块是 Glide 框架中至关重要的一部分&#xff0c;它负责协调…...

每天记录一道Java面试题---day32

MySQL索引的数据结构、各自优劣 回答重点 B树&#xff1a;是一个平衡的多叉树&#xff0c;从根节点到每个叶子节点的高度差不超过1&#xff0c;而且同层级的节点间有指针相互连接。在B树上的常规检索&#xff0c;从根节点到叶子节点的搜索效率基本相当&#xff0c;不会出现大…...

Vue3 Pinia 符合直觉的Vue.js状态管理库

Pinia 符合直觉的Vue.js状态管理库 什么时候使用Pinia 当两个关系非常远的组件&#xff0c;要传递参数时使用Pinia组件的公共参数使用Pinia...

深度学习与大模型基础-向量

大家好&#xff01;今天我们来聊聊向量&#xff08;Vector&#xff09;。别被这个词吓到&#xff0c;其实向量在我们的生活中无处不在&#xff0c;只是我们没注意罢了。 1. 向量是什么&#xff1f; 简单来说&#xff0c;向量就是有大小和方向的量。比如你从家走到学校&#x…...

【网络编程】完成端口 IOCP

10.11 完成端口 10.11.1 基本概念 完成端口的全称是I/O 完成端口&#xff0c;英文为IOCP(I/O Completion Port) 。IOCP是一个异 步I/O 的 API, 可以高效地将I/O 事件通知给应用程序。与使用select() 或是其他异步方法不同 的是&#xff0c;一个套接字与一个完成端口关联了起来…...

《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)

目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...

管理网络安全

防火墙在 Linux 系统安全中有哪些重要的作用&#xff1f; 防火墙作为网络安全的第一道防线&#xff0c;能够根据预设的规则&#xff0c;对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问&#xff0c;只允许符合规则的流量进入系统&#xff0c;从而保护系统免受…...

明日直播|Go IoT 开发平台,开启万物智联新征程

在物联网技术飞速发展的当下&#xff0c;物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境&#xff0c;实现高效、便捷开发的有力工具。 3 月 11 日&#xff08;星期二&#xff09;19:00&#xff0c;GitCode 特别邀请独…...

系统架构设计师—系统架构设计篇—软件架构风格

文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格&#xff08;数据共享风格&#xff09;数据库系统黑板系统超文本系统 闭…...

【MySQL_04】数据库基本操作(用户管理--配置文件--远程连接--数据库信息查看、创建、删除)

文章目录 一、MySQL 用户管理1.1 用户管理1.11 mysql.user表详解1.12 添加用户1.13 修改用户权限1.14 删除用户1.15 密码问题 二、MySQL 配置文件2.1 配置文件位置2.2 配置文件结构2.3 常用配置参数 三、MySQL远程连接四、数据库的查看、创建、删除4.1 查看数据库4.2 创建、删除…...

【Zinx】Day5-Part4:Zinx 的连接属性设置

目录 Day5-Part4&#xff1a;Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4&#xff1a;Zinx 的连接属性设置 在 Zinx 当中&#xff0c;我们使用 Server 来开启服务并监听指定的端口&#xff0c;当接收到来自客户端的连接请求…...

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…...

小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡

在微信小程序中&#xff0c;事件分为 冒泡事件 和 非冒泡事件 &#xff1a; 冒泡事件&#xff1a;当一个组件的事件被触发后&#xff0c;该事件会向父节点传递&#xff1b;&#xff08;如果父节点中也绑定了一个事件&#xff0c;父节点事件也会被触发&#xff0c;也就是说子组…...

全球首款 5G-A 人形机器人发布

全球首款 5G-A 人形机器人于世界移动通信大会&#xff08;MWC2025&#xff09;上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍&#xff1a; 名称与背景 名称9&#xff1a;这款人形机器人名为 “夸父”&#xff0c;是中国移动、华为与乐聚机器人在 GTI 平台…...

Tomcat 新手入门指南

Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器&#xff0c;广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南&#xff0c;帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...

Flink-DataStreamAPI-生成水印

下面我们将学习Flink提供的用于处理事件时间戳和水印的API&#xff0c;也会介绍有关事件时间、流转时长和摄取时间&#xff0c;下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间&#xff0c;Flink需要知道事件时间戳&#xff0c;这意味着流中的每个元素都需要…...

【单片机】ARM 处理器简介

ARM 公司简介 ARM&#xff08;Advanced RISC Machine&#xff09; 是英国 ARM 公司&#xff08;原 Acorn RISC Machine&#xff09; 开发的一种精简指令集&#xff08;RISC&#xff09; 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性&#xff0c;成为嵌入式系统、移动…...

Flutter——最详细原生交互(MethodChannel、EventChannel、BasicMessageChannel)使用教程

MethodChannel&#xff08;方法通道&#xff09; 用途&#xff1a;实现 双向通信&#xff0c;用于调用原生平台提供的 API 并获取返回结果。 场景&#xff1a;适合一次性操作&#xff0c;如调用相机、获取设备信息等。 使用步骤&#xff1a; Flutter 端&#xff1a;通过 Meth…...

Kafka常用指令(详细)

Kafka常用指令&#xff08;详细&#xff09; 启停命令 前台启动 前台启动命令 ./bin/kafka-server-start.sh config/server.properties 后台启动方式1 后台启动命令加上参数-daemon&#xff0c;窗口关闭之后kafka后台程序继续运行 ./bin/kafka-server-start.sh -daemon co…...

供应链工作效率如何提升

提升供应链工作效率可以从以下几个关键方面入手&#xff1a; 1. 优化供应链管理 数据驱动决策&#xff1a;利用AI和大数据分析&#xff0c;提高预测准确性&#xff0c;优化库存管理。供应链可视化&#xff1a;采用ERP&#xff08;企业资源计划&#xff09;和SCM&#xff08;供…...

1-001:MySQL的存储引擎有哪些?它们之间有什么区别?

MySQL 存储引擎 ├── InnoDB&#xff08;默认引擎&#xff09; │ ├── 事务支持&#xff1a;支持 ACID 和事务&#xff08;事务日志、回滚、崩溃恢复&#xff09; │ ├── 锁机制&#xff1a;支持行级锁&#xff0c;提高并发性能 │ ├── 外键支持&#xff1a;支持外键…...

Java/Kotlin逆向基础与Smali语法精解

1. 法律警示与道德边界 1.1 司法判例深度剖析 案例一&#xff1a;2021年某游戏外挂团伙刑事案 犯罪手法&#xff1a;逆向《王者荣耀》通信协议&#xff0c;修改战斗数据包 技术细节&#xff1a;Hook libil2cpp.so的SendPacket函数 量刑依据&#xff1a;非法经营罪&#xff…...

用AI学编程4——swift学习1

一个swift文件&#xff0c; 整理出swift从入门到精通的所有知识点&#xff0c; 给出注释&#xff0c; 给出这样的swift文件 以下是一个整合了 Swift 从入门到精通的主要知识点的 Swift 文件&#xff0c;包含了基础语法、面向对象编程、异常处理、集合框架、多线程、Lambda 表达…...

数据集构建与训练前准备

训练数据集目录结构与格式 作者笨蛋学法&#xff0c;先将其公式化&#xff0c;后面逐步自己进行修改&#xff0c;读者觉得看不懂可以理解成&#xff0c;由结果去推过程&#xff0c;下面的这个yaml文件就是结果&#xff0c;我们去推需要的文件夹(名字可以不固定&#xff0c;但是…...

在大型语言模型的提示词设计中,system、user和assistant三个角色的区别与联系

在大型语言模型的提示词设计中,system、user和assistant三个角色承担不同的功能,其区别与联系如下: 1. 角色定义与功能 system(系统指令) 作用:设定模型的整体行为、角色定位和任务框架。例如,“你是一位专业的科技作家”或“仅回答与医疗相关的问题”。特点:在多轮对话…...

Zabbix监控进程报警(Zabbix Monitoring Process Alarm)

zabbix监控进程占cpu、内存、磁盘RAID情况 1、cpu达到90%时报警 名称: cpu user percent gt 90% 表达式&#xff1a;{Template OS Linux:system.cpu.util[,idle].avg(1m)}<10 2、内存达到80%时报警 配置—主机(选择监控主机)—监控项—创建监控项 1、创建监控项 名称&…...

p5.js:sound(音乐)可视化,动画显示音频高低变化

本文通过4个案例介绍了使用 p5.js 进行音乐可视化的实践&#xff0c;包括将音频振幅转化为图形、生成波形图。 承上一篇&#xff1a;vite&#xff1a;初学 p5.js demo 画圆圈 cd p5-demo copy .\node_modules\p5\lib\p5.min.js . copy .\node_modules\p5\lib\addons\p5.soun…...

HAL库常用函数

一、通用函数 系统初始化&#xff1a; HAL_Init(): 初始化HAL库和系统时钟&#xff08;调用前需配置系统时钟源&#xff09;。 HAL_Delay(uint32_t Delay): 毫秒级阻塞延时&#xff08;基于SysTick定时器&#xff09;。 HAL_GetTick(): 获取系统运行时间&#xff08;毫秒计数…...

【Zinx】Day5-Part3:Zinx 的连接管理

目录 Day5-Part3&#xff1a;Zinx 的连接管理创建连接管理模块将连接管理模块集成到 Zinx 当中将 ConnManager 集成到 Server 当中在 Connection 的工厂函数中将连接添加到 ConnManagerServer 中连接数量的判断连接的删除 补充&#xff1a;连接的带缓冲发包方式补充&#xff1a…...

C语言:6.20字符型数据练习题

编写程序,输人一行数字字符(用回车结束),每个数字字符 的前后都有空格。 把这一行中的数字转换成一个整数。 例如,若输入(<CR>代表 Enter键):2 4 8 3<CR>则输出 整数:2483。 #include <stdio.h>int main() {char ch;int number 0;printf("请输入一行…...