用于较长任务的后台线程

Posted

技术标签:

【中文标题】用于较长任务的后台线程【英文标题】:Background threading for longer tasks 【发布时间】:2021-03-17 19:28:57 【问题描述】:

我使用 SwiftUI 框架构建了一个 ios 应用程序。 我想根据用户是否正在运行长时间运行任务。 因此,我使用 Combine 框架来启动和停止一些与运行活动相关的进程,这些进程使用服务质量为 .background 的后台线程。 但是,我注意到有时启动和停止的过程会延迟或终止。 我可以延迟这个过程,但我不能接受它被杀死。

我想知道我该如何解决这个问题? 因为如果您使用谷歌地图并点击您所在位置的开始导航。 该过程不会被杀死。 所以必须有办法让后台线程上的进程启动更长时间。我只是不知道怎么做。 有什么想法吗?

        self.activaity.$running
        .subscribe(on: self.BackgroundQueue)
        .receive(on: self.BackgroundQueue)
        .removeDuplicates(by: $0 == $1)
        .sink(receiveValue:  [self] value in
                if value 
                        self.start()
                
                else
                        self.stop()
                
        )
        .store(in: &self.cancellables)   


func start() 
    self.persistMetaData()
    self.persist()
    self.sensorManager.startUpdates()
   
        

谢谢

【问题讨论】:

如果不显示一些代码,就无法回答这个问题。此外,谷歌地图导航(后台进程)与在不同线程上的组​​合调用被杀死是完全不同的。 你如何获得你的进程被杀死的信息?你能显示代码吗? 我编辑并添加了一些代码。 我实际上并不确定线程​​是否被杀死。但从数据的角度来看,似乎是这样。 线程不只是在 iOS 上神秘地被杀死,所以还有其他事情发生。由于您还没有显示self.activaity.$running 是什么,因此很难说发生了什么。此外,没有理由将所有这些都包含在self.BackgroundQueue.async 中——你已经在做.receive(on: self.BackgroundQueue)。尝试编辑问题以显示一个最小的、可重复的示例 【参考方案1】:

在 iOS 中,“后台”一词有两种不同的含义:在后台线程上运行,或者当您的应用不再是最前端的应用但仍在获得处理时间时。

两者只是松散相关。启动在后台线程上运行的任务与设置应用程序以在用户将其切换到后台或锁定设备后继续获取 CPU 时间不同。

后台线程是通过代码的单独执行路径,通常(但不总是)在不同的处理器上运行,并且通常与主线程同时运行。就像你在厨房里有两个厨师,都在做不同的菜。他们必须共享相同的设备和用品,如果一个厨师弄得一团糟,或者偷了两个厨师准备好的食材,就会搞砸厨师两个。同样,多个线程必须注意不要同时访问同一内存,而无法同步该访问,或者同时与硬件系统通信。

为了理解背景的其他含义,我们需要谈谈操作系统如何管理应用程序。如果您的应用程序是最前面的应用程序,它会在前台运行。通常,如果用户交换应用程序,您会收到一条通知,表明您将被暂停。您应该停止运行计时器并保存应用程序的数据。您可以要求额外的时间在后台继续运行,但这通常最多只有 3 分钟左右。 (在这个词背景的意义上,这意味着您的应用程序在另一个应用程序在屏幕上并且用户正在与之交互时继续执行诸如下载文件或记录 GPS 读数之类的事情。)

可能在后台运行一小段时间后,您的应用会切换到“暂停”状态。在这种状态下,它不会获得任何处理器时间。 (您的应用程序的线程没有任何处理器时间。)一旦处于挂起状态,它可以随时终止(从内存中删除并终止),无需另行通知。如果它被杀死,它的所有线程都会被杀死,并且它在内存中的所有状态数据都会丢失。这就是为什么当你被告知你即将被暂停时,你应该保存你的应用状态。

允许在后台无限期运行数量非常有限的应用类型(逐步导航应用、流媒体音乐应用以及其他一两个应用)。 (我相信 HealthKit 应用程序是允许在后台连续运行的另一种应用程序类型,尽管我从未详细研究过 HealthKit。)Apple 限制了可以在后台运行的应用程序,因为 CPU 占用了大量资源全速运行时功率更大,获得任何 CPU 时间的功率更大。 Apple 只允许非常特定的应用程序在后台运行,并且只有在用户授权他们这样做时。这让 Apple(和用户)可以限制功耗并延长电池寿命。在后台运行的应用程序也会降低前台应用程序的性能,尽管硬件可以限制后台应用程序来防止这种情况。你的例子,谷歌地图,是一个转弯导航应用程序。它这样声明自己,在 iOS 让它继续在后台运行之前,用户必须授予它这样做的权限。

忽略这些类型的应用并返回您的应用:

如果用户在您的应用暂停时切换回您的应用,它会从停止的地方重新开始,所有状态变量都保持不变,并且前台线程和任何正在运行的后台线程再次开始获得 CPU 时间。

当您的应用程序终止时,所有后台线程都会随之终止。当它重新启动时,您将不得不启动任何您想再次运行的后台线程。

当用户切换到另一个应用程序时,在后台线程上启动任务不会让您的应用程序继续运行。同样,背景一词的两种用法意味着完全不同的东西。

【讨论】:

哦,好的,我明白你所说的与州有关的内容。好的,这正是当用户进入应用程序并且运行为真并且用户进入后台应用程序仍然运行时发生的情况。但是,当用户进入应用程序并且 running 不是 true 时,它​​不会触发进程,并且当 running 是 true 并且进程启动时。现在我的问题是我该如何解决?我必须以不同的方式解决问题吗? 我没有详细研究过 HealthKit。我强烈怀疑有一种机制可以请求后台访问健康数据,即使您的应用程序处于后台或应用程序处于睡眠状态。我建议你研究一下。

以上是关于用于较长任务的后台线程的主要内容,如果未能解决你的问题,请参考以下文章

Android中使用IntentService运行后台任务

H5新特性-WebWorker

在后台线程执行硬任务,在主线程返回结果

饭店的运作模式(线程线程池任务)

执行后台任务——AsyncTask 的替代方案?

在 iOS 中定期在后台线程中运行任务