1.《Exploring in UE4》多线程机制详解[原理分析]
2.Spring的码详@EnableAsync与@Async使用详解
3.JobIntentService源码解析
《Exploring in UE4》多线程机制详解[原理分析]
多线程是优化项目性能的重要方式之一,游戏也不例外。码详尽管有观点认为“游戏不适合利用多线程优化”,码详但实际上游戏中多线程的码详应用非常广泛,如渲染模块、码详物理模块、码详华为提供源码审查网络通信、码详音频系统、码详IO等。码详UE4引擎运行时展示的码详线程数量可能比您想象的要多。
尽管UE4遵循C++标准,码详但它并没有使用std::thread,码详而是码详自实现了一套多线程机制,这类似于Java的码详用法。如果您想使用std::thread,码详也是完全可以的。
在UE4中,骑士卡系统源码您可以创建继承自FRunnable接口的单个线程,也可以直接创建AsyncTask来调用线程池中空闲的线程,还可以通过TaskGraph系统异步完成自定义任务。尽管本质相同,但用法不同,理解上也需要花费不少时间。本文将对各种机制进行分析并总结,但不会深入讨论线程的实现原理和线程安全等内容。由于个人接触多线程编程时间不长,有些内容可能不够准确,欢迎共同讨论。
首先,我们从最基本的方式来创建线程,即创建一个继承自FRunnable的类,将任务分发给其他线程执行。FRunnable是期货稳健指标源码一个简单的类,包含5到6个函数接口,为了与真正的线程区分,我们将其称为“线程执行体”。
关于FQueuedThreadPool线程池,它类似于一般的线程池实现,维护了多个线程FQueuedThread和多个任务队列IQueuedWork。在线程池中,所有线程都是FQueuedThread类型,它们是继承自FRunnable的线程执行体,每个FQueuedThread包含一个FRunnableThread作为内部成员。
接下来,我们谈谈更复杂的AsyncTask系统,它是一套基于线程池的异步任务处理系统。在使用搜索引擎搜索UE4多线程时,可能会看到类似官方代码中的异步处理解决方案示例。这个所谓的java源码头条多线程用法看似简单,但实际上也是基于Runnable的方式实现的,只是封装得更深,需要深入源码才能理解其原理。
TaskGraph系统是UE4一套抽象的异步任务处理系统,可以创建多个多线程任务,并指定任务之间的依赖关系,按照该关系依次处理任务。具体实现方式网上有很多案例,建议先了解其用法。
TaskGraph系统中的任务与线程可以创建多个Task任务并分配给不同的线程执行。在TaskGraph系统中,任务类也是我们自行创建的,如FTickFunctionTask、FReturnGraphTask等,其中需要声明DoTask函数来表示要执行的任务内容,GetDesiredThread函数来表示要在哪个线程上执行。runtime源码编译2021
最后,我们总结了三种使用多线程的方式,每种机制都有很多技术点值得我们深入学习。对于消耗大、复杂的任务,不建议使用TaskGraph。对于简单的任务或想方便实现线程之间的依赖等待关系,可以直接使用TaskGraph。
Spring的@EnableAsync与@Async使用详解
@EnableAsync注解允许Spring启动异步方法执行,类似于XML配置方式。当与@Configuration结合使用时,整个Spring环境将启用基于注解的异步处理。
异步方法执行默认使用关联的线程池。若无匹配bean,Spring将使用SimpleAsyncTaskExecutor,它为每个新任务创建新线程。若异步方法返回值为void,调用过程中的异常信息无法返回给调用者,通常仅记录日志。
自定义线程池和异常处理需实现AsyncConfigurer接口。若仅自定义一个,另一个可直接返回null,Spring将使用默认设置。使用AsyncConfigurerSupport扩展接口,可以全面配置。注意,当ThreadPoolTaskExecutor未被Spring管理时,可添加@Bean注解使其成为管理Bean。加入容器后,无需手动调用initialize方法,它在Bean初始化时自动执行。
XML配置与基于javaconfig的示例功能等效,除了给Executor添加线程名字前缀。javaconfig方式提供更全面的配置。@EnableAsync注解的mode()属性控制切面应用:默认AdviceMode.PROXY,其他属性共同控制代理方式;若设置AdviceMode.ASPECTJ,则proxyTargetClass属性被忽略,此时需要spring-aspects相关模块的jar包,并且方法内部调用也会被拦截。
@Async标注用于标记异步执行的方法,可加在方法或类上。加在类上表示类中所有方法均为异步执行。目标方法参数任意,返回值只能为void或Future,可以是ListenableFuture或CompletableFuture,以便更好地与异步任务交互。非future类型的返回值无法获取。
探究EnableAsync源码,了解其内部工作流程。关注ProxyAsyncConfiguration配置类,它在PROXY模式下由Spring注入。分析AsyncAnnotationBeanPostProcessor,了解Executor和ExceptionHandler的配置过程。异步方法执行通过AnnotationAsyncExecutionInterceptor拦截器实现,最终在AsyncExecutionAspectSupport类中确定使用的Executor。
详细实现步骤和测试代码可在GitHub上的相应仓库中找到。欢迎扫码关注以获取更多资源和信息。
JobIntentService源码解析
Android 8.0引入了更严格的系统资源管控,包括后台限制规则。
在Android 8.0中,禁止应用在后台运行时创建Service。
若应用在后台运行,将会收到错误提示。
JobIntentService是Android 8.0中新增的类,继承自Service。
该类用于执行加入队列的任务。对于Android 8.0及以上系统,JobIntentService任务将通过JobScheduler.enqueue执行,而8.0以下系统则继续使用Context.startService。
JobIntentService使用便捷,只需调用YourService.enqueueWork(context, new Intent())方法。
相较于JobService,JobIntentService简化了操作,开发者无需关注其生命周期,避免了在后台运行时创建Service导致的crash问题,且通过静态方法即可启动。
源码解析如下:首先记录几个关键变量的含义。
在Android 8.0以上的系统中,执行流程如下。
work的具体逻辑处理在何处?
通过JobService的工作原理,查找onStartJob方法。
最终,处理work的逻辑会流转至AsyncTask中,通过protected abstract void onHandleWork(@NonNull Intent intent)方法实现。
子类需实现jobIntentService处理work,使用线程池的AsyncTask执行,无需考虑主线程阻塞问题。
针对Android 8.0以下系统,流程如下:回到onStartCommand方法。
同样,最终会流转至Asynctask任务执行onHandleWork。