当前位置: 首页 > 科技观察

Android中进程和线程调度的nice

时间:2023-03-14 19:59:15 科技观察

分析在计算机操作系统中,进程是资源分配和调度的基本单位,每个进程内也可以存在多个线程。那么在Android系统(LinuxKernel)中,进程是如何抢占资源的,线程又是如何根据优先级进行切换的呢?本文将尝试分析这个问题,研究nice在Linux和Android系统中的应用。一些概念进程是计算机系统中运行程序的实体,也是线程的容器。线程是进程中的实际执行单元,线程是程序执行流程的最小单位。一个进程中可以有多个线程。nice与进程调度在Linux中,nice值(以下简称nice值)用于设置进程的优先级,系统任务调度器根据nice值合理安排调度。nice的取值范围是-20到19。通常情况下,nice的默认值为0。取决于具体的操作系统。nice的值越大,进程的优先级越低,获得CPU调用的机会越少。nice值越小,进程的优先级越高,获得CPU调用的机会越多。nice值为-20的进程优先级最高,nice值为19的进程优先级最低。从父进程fork出来的子进程的nice值与父进程的nice值是一样的。父进程renice,子进程nice值不会相应改变。词源精妙。nice命令的出处几乎没有任何资料,所以我试着自己推断一下。词霸、沪江等辞书所给的义,都是好的;美丽的;迷人的;善良和友好。有道词典则给了一点其他词典没有的亲切感。个人觉得有道给的比较合理。要想善良,就要谦虚,多多少少牺牲自己去帮助别人。所以nice值越高,你越善良,但是你的优先级就会越低。renice对于一个新的进程,我们可以按照下面的代码来设置一个进程的nice值。nice-n10adblogcat对于创建的进程,我们可以使用renice修改nice值sudorenice-n0-p24161该命令需要使用root权限,-p对应的值为进程id。注意Linux发行版中renice命令的-n值应该是进程的目标优先级。而在mac下-n代表当前权限的增加值。比如在Mac下,如果一个进程的nice值从19变成10,就可以这样操作sudorenice-n-9-p24161。需要注意这一点,以免掉坑。NiceinAndroid由于Android是基于Linux内核的,因此在Android中也有nice的价值。但总的来说,我们无法控制,原因如下:Android系统不像其他Linux发行版那样方便使用nice命令。renice需要root权限,一般应用无法实现。线程调度虽然我们无法控制进程的优先级,但是我们可以控制进程中线程的优先级。Android中有两种线程优先级,一种是AndroidAPI版本,一种是Java原生版本。AndroidAPIAndroid中的线程优先级目前规定如下。了解了进程优先级和nice值的关系之后,线程优先级和nice值的关系就比较容易理解了。THREAD_PRIORITY_DEFAULT,默认线程优先级,值为0。THREAD_PRIORITY_LOWEST,线程级别最低,值为19。THREAD_PRIORITY_BACKGROUND建议为后台线程设置该优先级,值为10。THREAD_PRIORITY_FOREGROUND用户所在的UI线程互动。这个优先级不能在代码中设置。系统会根据情况调整到这个优先级,值为-2。THREAD_PRIORITY_DISPLAY也是与UI交互相关的优先级类别,但它的优先级高于THREAD_PRIORITY_FOREGROUND。代码中无法设置,由系统根据情况调整。该值为-4。THREAD_PRIORITY_URGENT_DISPLAY显示线程的最高级别,用于处理绘图屏幕和检索输入事件,代码中不能设置为该优先级。该值为-8。THREAD_PRIORITY_AUDIO音频线程的标准级别,代码中不能设置为该优先级,取值为-16。THREAD_PRIORITY_URGENT_AUDIO最高级别的音频线程,优先级高于THREAD_PRIORITY_AUDIO。此优先级不能在代码中设置。该值为-19。THREAD_PRIORITY_MORE_FAVORABLE略优于THREAD_PRIORITY_DEFAULT,值为-1。THREAD_PRIORITY_LESS_FAVORABLE略微落后于THREAD_PRIORITY_DEFAULT,值为1。使用AndroidAPI设置线程优先级也很简单,只需要在线程执行时调用android.os.Process.setThreadPriority方法即可。这种在线程运行时修改优先级的效果类似于renice。newThread(){@Overridepublicvoidrun(){super.run();android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);}}。开始();Java原生APIJava提供了三个级别的Thread设置,MAX_PRIORITY,相当于android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY,值为10。MIN_PRIORITY,相当于android.os.Process.THREAD_PRIORITY_LOWEST,值为0。NORM_PRIORITY,相当于android.os.Process.THREAD_PRIORITY_DEFAULT,值为5。使用setPriority我们可以设置一个线程的优先级,使用getPriority可以得到一个线程的优先级。在Android系统中,不推荐使用Java原生API,因为Android提供的API层次较多,更适合在Android系统中设置详细的优先级。注意AndroidAPI的线程优先级和Java原生API的优先级是相对独立的。例如,使用android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)后,使用Java原生API获取的值,Thread.getPriority()不会改变。比如下面的代码:newThread(){@Overridepublicvoidrun(){super.run();Log.i(LOGTAG,"JavaThreadPriorityBefore="+Thread.currentThread().getPriority());过程。setThreadPriority(Process.THREAD_PRIORITY_LOWEST);Log.i(LOGTAG,"Java线程优先级="+Thread.currentThread().getPriority());}}。开始();以上代码的运行日志为I/MainActivity(3679):JavaThreadPriorityBefore=5I/MainActivity(3679):JavaThreadPriority=5由于存在上述缺陷,我们在分析ANRtrace时需要注意。在下面的ANR日志信息中,proi中prio=5的值对应Java原生API的线程优先级。nice=-6中的nice表示AndroidAPI版本的线程优先级。“主要”prio=5tid=1本地|group="main"sCount=1dsCount=0obj=0x41690f18self=0x4167e650|sysTid=1765nice=-6sched=0/0cgrp=appshandle=1074196888|state=Sschedstat=(000)utm=5764stm=3654core=2#00pc00022624/system/lib/libc.so(__futex_syscall3+8)#01pc0000f054/system/lib/libc.so(__pthread_cond_timedwait_relative+48)#02pc0000f0b4/system/lib/libc.so(__pthread_cond_timedwait+64)避免ANR我在上一篇关于Android中ANR的文章中提到,使用WorkerThread来处理耗时的IO操作,同时降低WorkerThread的优先级,对于耗时的IO操作,比如读取数据库,文件等,我们可以将workerThread的优先级设置为THREAD_PRIORITY_BACKGROUND,以减少与主线程的竞争能力。