【解锁创意之门:环境变量引领你的编程奇思妙想】(上)

简介: 【解锁创意之门:环境变量引领你的编程奇思妙想】

【本节重点】


  • 了解进程调度,Linux进程优先级,理解进程竞争性与独立性,理解并行与并发
  • Linux的调度与切换,了解Linux2.6内核中进程队列的数据结构
  • 理解环境变量,熟悉常见环境变量及相关指令, getenv/setenv函数
  • 理解C内存空间分配规律,了解进程内存映像和应用程序区别, 认识地址空间。


1.进程优先级


前提:进程要访问某种资源,进程进行通过一定的方式(排队),确认享受资源的先后顺序。


1.1.基本概念


  • cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。


提问:优先级 vs 权限


       权限绝对的是能不能的问题,而优先级决定的是你先还是我先的问题,说白了,只要到了优先级,大概率一定是你拥有享受这个资源的权限了,只不过需要通过优先级确定先后的问题。


为什么要有优先级呢?


我们可以想一想,如果我们在食堂打饭的时候,打饭的人比学生多,那么学生就不用排队,可是现在打饭的人明显少于学习,所以学生就要排队,进程也是如此,因为系统的资源过少!但是这是一个相对概念,只有在中午去食堂买饭就需要排队,而在下午三四点去买饭就不用排队!这也就解释了CPU为什么有运行队列,因为CPU只有一个,资源过少,每个进程想获取CPU就必须要排对,进程需要通过队列确认优先级去获得CPU的访问,如果我们电脑的CPU很多,那就不需要队列了,直接运行进程就行啦。


1.2.查看系统进程



我们先写一份上面的代码,然后执行一下,同时输入在右侧输入:ps -al


ps -al 是一个用于显示进程信息的命令,常用于Linux。下面是对该命令的解释:


  • ps: 这是进程状态的缩写,是一个用于报告当前进程状态的命令。
  • -a: 显示所有终端上的进程,而不仅仅是与当前用户相关的进程。
  • -l: 以长格式显示输出。长格式包括更多的列,提供更详细的信息。


我们很容易注意到其中的几个重要信息,有下:

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值


这里我就要插几句话啦!不要把优先级想象的特别复杂,它在sturck task_struct里面就是一个整型变量,而且上面我们观察到Linux下默认优先级是80,但是Linux的优先级是可以被修改的,但是Linux优先级是有区间的,其范围是[60,99],一共40个。Linux优先级本质就是整型变量数字,数字越小,优先级越高!


1.3.PRI and NI


  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小 进程的优先级别越高
  • 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
  • PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
  • 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
  • 所以,调整进程优先级,在Linux下,就是调整进程nice值
  • nice其取值范围是-20至19,一共40个级别。


1.4.PRI vs NI


  1. 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
  2. 可以理解nice值是进程优先级的修正修正数据


1.5.用top命令更改已存在进程的nice:


       Linux系统允许用户调整优先级,但是不能直接让你修改PRI,而是通过修改nice值,它不是优先级,而是进程优先级的修正数据!现在我们来演示一下优先级的修改。


结果展示:


根据这个公式:PRI(new)=PRI(old)+nice,我们再恢复出原来的优先级


咦!这是什么情况!!!


nice值是通过覆盖式的写入的,但是我们的PRI不应该是80 = 90 + (-10)嘛,为什么是70呢?其实这是正常的,你想想如果我们的PRI是80,那我们的nice就是-10了,而其他进程nice值是0,这样系统的数据就不一致了,所以PRI在每一次设置的时候,PRI(old)都是80。


我们再来测试一下nice其取值范围


首先我们将nice值干到100。


然后我们将nice值干到-100。


总结:nice其取值范围是-20至19,一共40个级别,Linux优先级是有区间的,其范围是[60,99],一共40个,两个相互对应。


提问:Linux为什么调整优先级是受收限制的?


       如果允许任意进程调整优先级,用户可能会将自己的进程提升到高优先级,自己的进程抢占系统资源,使其他进程无法正常运行,无法享受到CPU等其他资源,此时其他进程很难得到资源,此时就被称为进程饥饿问题。任何得分时操作系统,调度上,都要具有较为公平的进行调度,所以就要求优先级是受收限制的。


2.Linux的调度与切换


概念准备:


  1. 进程在运行的时候,放在CPU上,必须直接把代码跑完,才行吗???不行,这很明显,如果我们写一个死循环的代码,那么CPU永远都跑不完,其他进程也就永远得不到调度,那么此时系统就卡死了。所以现代操作系统都是基于时间片轮转进行轮转执行的!!!  
  2. 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  3. 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
  4. 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为 并行
  5. 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为 并发


2.1.进程切换



我们可以在struct task_struct查看到这些硬件上下文。


所以进程切换的过程就是:进程在CPU上运行 -> 时间片用完,保存硬件上下文 -> 运行队列进程阻塞 ->时间片轮转到该进程,恢复硬件上下文。这也就是一个进程在CPU一整个周期的情况。


2.2.进程调度


前提:Linux实现进程调度算法需要考虑优先级,考虑饥饿,还要考虑效率


上图是Linux2.6内核中进程队列的数据结构,我们先不看,后面我会基于上面的画一个。


2.2.1.一个CPU拥有一个runqueue


  • 如果有多个CPU就要考虑进程个数的负载均衡问题


2.2.2.优先级


  • 普通优先级适用于一般用户进程,它们不需要对实时性有极高的要求。这些进程的调度是基于时间片轮转的,并且由操作系统决定它们在CPU上运行的时间。普通优先级:100~139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
  • 实时优先级是为具有严格时间要求的任务设计的,这些任务需要在确定的时间内完成。实时优先级:0~99(不关心)


2.2.3.活动队列


  • 时间片还没有结束的所有进程都按照优先级放在该队列
  • nr_active: 总共有多少个运行状态的进程
  • queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下 标就是优先级!
  • 从该结构中,选择一个最合适的进程,过程是怎么的呢?


1. 从0下表开始遍历queue[140]

2. 找到第一个非空队列,该队列必定为优先级最高的队列

3. 拿到选中队列的第一个进程,开始运行,调度完成!

4. 遍历queue[140]时间复杂度是常数!但还是太低效了!

  • bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个 比特位表示队列是否为空,这样,便可以大大提高查找效率!


2.2.4.过期队列


  • 过期队列和活动队列结构一模一样
  • 过期队列上放置的进程,都是时间片耗尽的进程
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算
  • 如果我们的一个进程的时间片已经轮转完,它就应该从活跃队列中剥离出来,而成为新进程进入来过期队列中。


2.2.5.active指针和expired指针


  • active指针永远指向活动队列
  • expired指针永远指向过期队列
  • 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
  • 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程!


上图是Linux2.6内核中进程队列的数据结构,之间关系也已经给大家画出来,方便大家理解。


2.2.6.总结


       在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增 加,我们称之为进程调度O(1)算法!


补充:参考文档 


3.环境变量


3.1.mian参数 --- 命令行参数 --- 掌握


我们知道main函数是有形参的,只不过我们一直没有使用过,今天我们来看一下main函数的参数,看看main函数的参数是什么意思?它和密命令行参数有什么关系?


首先我们知道argv是一个指针数组,数组元素有argc个,它里面的元素类型都是char*的,而我们知道char*指向的是字符串的首地址,我们来看一下argv里面的每个char*都指向了那个字符串?


我们发现随之我们的程序执行,当我们以空格作为分隔符传入-a,-b,-c,程序按照空格为分隔符,依次传入一个一个子串到argv这个指针数组里面,同时每传入一个字串,argc的个数就会加一。现在我再来解释一下输出内容。


所以我们在命令行上输入以空格为分隔符输入的字符串,会被bash解析一个一个子串,维护成指针数组argv,同时还维护了一个计数器argc,只要是函数它就会被调用,main函数也不例外,main函数由系统调用,bash会把参数传入给main函数,所以我们的main函数就拿到了命令行上输入以空格为分隔符输入的字符串和计数器argc,然后就输出了上述的结果。整个传入main函数的参数我们可以称之为一张表,我们称之为命令行参数表,把这张表就传给当前进程,而且整张表必须以NULL为结尾。那么我们的程序还可以这样写:


【解锁创意之门:环境变量引领你的编程奇思妙想】(中):https://developer.aliyun.com/article/1425753

相关文章
|
机器学习/深度学习 人工智能 Java
学会用AI:释放创意,解放双手,工作再多也不慌
随着人工智能(AI)技术日渐成熟,AI在软件开发领域的应用也更加广泛。以前我们谈到AI时,常常会想到复杂的算法和深奥的理论,但如今,AI正在悄然改变着程序员的日常工作方式。从AI代码生成模型到AI编程助手应用,它们不仅仅是一小部分,更是未来程序开发的新趋势。
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
“解锁未来之钥:探索神经网络——那些正在改变世界的智能引擎背后的奥秘,让你见识前所未有的科技魅力”
【10月更文挑战第11天】神经网络是一种模拟人脑结构与功能的计算模型,通过学习数据模式进行预测或决策。基本单元为神经元,连接成层处理信息。本文介绍了神经网络的工作原理、结构及应用,并提供了一个使用Python和Keras构建简单神经网络解决二分类问题的示例。
30 3
|
1月前
|
数据采集 人工智能 测试技术
还在死磕AI咒语?北大-百川搞了个自动提示工程系统PAS
【10月更文挑战第4天】北京大学和百川智能研究人员开发了一种名为PAS的即插即用自动提示工程(APE)系统,利用高质量数据集训练的大型语言模型(LLMs),在基准测试中取得了显著成果,平均提升了6.09个百分点。PAS仅需9000个数据点即可实现顶尖性能,并能自主生成提示增强数据,提高了灵活性和效率。尽管存在训练数据质量和提示多样性等方面的潜在局限性,PAS仍为解决提示工程挑战提供了有前景的方法,有望提升LLM的可用性和有效性。论文详见:https://arxiv.org/abs/2407.06027。
41 3
|
3月前
|
Python
Python 控制结构:开启震撼编程之旅,犹如舞台上的精彩戏剧,让你的代码活起来!
【8月更文挑战第22天】Python的控制结构是编程的核心,包括条件判断(if-elif-else)和循环(for、while)。例如,可以用if-elif-else判断学生成绩等级,for循环计算1至10的总和,while循环实现猜数字游戏。此外,列表推导式等高级特性让操作更简洁高效。掌握这些结构能显著提升编程效率和代码质量。
53 1
|
3月前
|
UED 存储 自然语言处理
【语言无界·体验无疆】解锁Vaadin应用全球化秘籍:从代码到文化,让你的应用畅游世界每一个角落!
【8月更文挑战第31天】《国际化与本地化实战:构建多语言支持的Vaadin应用》详细介绍了如何使用Vaadin框架实现应用的国际化和本地化,提升用户体验和市场竞争力。文章涵盖资源文件的创建与管理、消息绑定与动态加载、日期和数字格式化及文化敏感性处理等方面,通过具体示例代码和最佳实践,帮助开发者构建适应不同语言和地区设置的Vaadin应用。通过这些步骤,您的应用将更加灵活,满足全球用户需求。
56 0
|
3月前
|
机器学习/深度学习 监控 自动驾驶
|
3月前
|
Python
编程之禅的奇幻之旅:探寻代码世界与生活万象的惊世共鸣,颠覆你的认知!
【8月更文挑战第7天】编程不仅是技术活,更融汇艺术与哲学。它启示我们在生活里追求简洁高效,如Python列表推导式的优雅;教会我们面对挑战时冷静分析,正如调试代码;体现分工合作的重要性,像模块化设计;并鼓励持续优化,提升效能。编程所蕴含的生活智慧,能引导我们创造更美好、有序的人生。
49 1
|
3月前
|
IDE 开发工具 计算机视觉
解锁Ruby图像处理新技能!从零基础到大师级,你的照片即将焕发不可思议的魔力!
【8月更文挑战第31天】Ruby不仅在Web开发和脚本编写中表现出色,还能通过强大的库如RMagick实现图像处理。RMagick是ImageMagick的Ruby接口,支持几乎所有图像格式。只需简单安装,即可进行图像加载、显示、滤镜应用、大小调整及裁剪等操作。
28 0
|
3月前
|
数据处理 Python
解锁Python多线程编程魔法,告别漫长等待!让数据下载如飞,感受科技带来的速度与激情!
【8月更文挑战第22天】Python以简洁的语法和强大的库支持在多个领域大放异彩。尽管存在全局解释器锁(GIL),Python仍提供多线程支持,尤其适用于I/O密集型任务。通过一个多线程下载数据的例子,展示了如何使用`threading`模块创建多线程程序,并与单线程版本进行了性能对比。实验表明,多线程能显著减少总等待时间,但在CPU密集型任务上GIL可能会限制其性能提升。此案例帮助理解Python多线程的优势及其适用场景。
39 0
|
6月前
|
存储 Shell Linux
【解锁创意之门:环境变量引领你的编程奇思妙想】(下)
【解锁创意之门:环境变量引领你的编程奇思妙想】