Android 何时以及为什么要使用一组执行者

Android 何时以及为什么要使用一组执行者,android,Android,我一直在读安卓文档中关于Executor的内容。如果我理解正确的话,它用于多线程管理,它可以为您做一些工作,比如在需要时生成新线程。或者你可以选择自己管理东西 在下面的示例中,使用了一组执行器而不是一个执行器。所以它有点像一个线程池(?) 为什么会选择使用一组遗嘱执行人?只有一个执行者无法实现的功能是什么?这只是为他们可能执行的正确作业构造和分配正确的执行者: 它很好地放在一个类中,便于重用 使用了三种类型的执行器,每种执行器用于它可以运行的特定类型的任务。请记住,执行器有线程来执行作业或Run

我一直在读安卓文档中关于Executor的内容。如果我理解正确的话,它用于多线程管理,它可以为您做一些工作,比如在需要时生成新线程。或者你可以选择自己管理东西

在下面的示例中,使用了一组执行器而不是一个执行器。所以它有点像一个线程池(?)


为什么会选择使用一组遗嘱执行人?只有一个执行者无法实现的功能是什么?

这只是为他们可能执行的正确作业构造和分配正确的执行者:

  • 它很好地放在一个类中,便于重用
  • 使用了三种类型的执行器,每种执行器用于它可以运行的特定类型的任务。请记住,执行器有线程来执行作业或
    Runnable
    s,执行器创建的每个线程一次可以运行一个作业:
    • diskIO
      是一个
      执行者。newSingleThreadExecutor()
      ,因为任务最好排队并一次执行一个,以减少写入和读取锁定或争用条件。因此,
      SingleThreadExecutor
      一次只运行一个任务,而不管有多少任务排队以确保该设计。作为一个单线程也可能意味着它被用于将应用程序日志写入一个文件,例如,该文件允许在提交给执行者时以正确的顺序写入日志。因此,单线程最擅长按照作业排队的顺序维护输出
    • networkIO
      是一个
      执行器。newFixedThreadPool(3)
      ,因为任务通常与网络相关,例如连接到internet上的服务器并执行请求或获取数据。这些任务通常会让用户等待(可能在几秒钟到几分钟之间),并且需要并行快速地执行,以便在需要同时执行多个请求的情况下缩短等待时间。因此,此执行器使用3个线程的原因是在它们之间分配任务并一起执行。这里不关心作业的顺序,因为作业执行所需的时间不同,但最重要的是它们是并行运行的
    • mainThread
      是一个
      MainThreadExecutor()
      在Android应用程序中处理UI并绘制它。用户界面应该运行平稳,不滞后,因此使用上述两个执行器的原因是让任何繁重的任务(如编写文件或执行请求)在后台运行,或与应用程序的
      主线程
      分开运行。即使应用程序没有向其提交任何任务,此执行器也会继续执行任务。它持续执行的任务是在屏幕上不断地绘制UI,并且不断地重复。由
      主线程执行的任务需要轻量级和快速(它们所花费的时间以毫秒为单位),因此任何减慢它的任务都会被注意到,因为
      mainThread
      正忙于完成该任务,而不是绘制和更新UI,因此UI将延迟或出现故障。这里的
      主线程
      只是使用了一个
      处理程序
      ,它是Android SDK/体系结构的一部分,是单线程类型,其行为类似于一个执行器(有一些区别),它将任务排队以创建/更新UI。只有
      处理程序
      可以执行UI任务,其他执行者都不能

  • 如何确定networkIO的线程数?例如,为什么不是2个或4个?啊,是的,决定线程数通常与设备中的内核数有关。我见过的一些gd标准是将核心数除以2,然后减去1,或者有时只是简单地从核心数中减去1。但这里的关键是,我们不希望应用程序通过占据所有核心来降低手机本身的速度(当然,应用程序不是手机上唯一的东西!其他东西也在运行),因此我认为最好采用分区。现在几乎所有的手机都有8核,所以这可能就是为什么选择了3核。
    /**
    * Global executor pools for the whole application.
    *
    * Grouping tasks like this avoids the effects of task starvation (e.g. disk 
    reads don't wait behind
    * webservice requests).
    */
    @Singleton
    open class AppExecutors(
    private val diskIO: Executor,
    private val networkIO: Executor,
    private val mainThread: Executor
    ) {
    
    @Inject
    constructor() : this(
        Executors.newSingleThreadExecutor(),
        Executors.newFixedThreadPool(3),
        MainThreadExecutor()
    )
    
    fun diskIO(): Executor {
        return diskIO
    }
    
    fun networkIO(): Executor {
        return networkIO
    }
    
    fun mainThread(): Executor {
        return mainThread
    }
    
    private class MainThreadExecutor : Executor {
        private val mainThreadHandler = Handler(Looper.getMainLooper())
        override fun execute(command: Runnable) {
            mainThreadHandler.post(command)
        }
    }
    }