- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
以前面试,面试官问了一个问题,大意是:
我们在终端中,通过执行 python main.py 命令,会启动一台前台进程直到程序结束。现在我还是想通过执行 python main.py ,启动一个后台进程,让后台进程运行我们的业务逻辑。这个时候应该怎么做呢?
回答上面这道题,需要先了解什么是前台进程和后台进程,什么是孤儿进程和僵尸进程?接下来,我们先一起看看前台进程和后台进程,以及孤儿进程和僵尸进程。最后再通过编写代码来完成面试题的需求.
在 Linux 中, 前台进程是指当前正在运行的进程,它与用户交互并占用终端 。当用户在终端中输入命令时,该命令所启动的进程就是前台进程.
前台进程会占用终端 ,直到它执行完毕或者被中断(例如按下 Ctrl+C)。在前台进程运行期间,用户可以通过键盘输入命令或者发送信号来与进程交互.
Linux 后台进程是指在终端中运行的进程,但是不会占用终端的输入输出,而是在后台运行 .
在 Linux 中,可以通过在命令后面加上 & 符号来将进程放到后台运行。例如,运行命令 command & 就可以将 command 进程放到后台运行.
后台进程可以在终端关闭后继续运行,也可以同时运行多个后台进程。可以使用 jobs 命令查看当前运行的后台进程,使用 fg 命令将后台进程切换到前台运行,使用 bg 命令将前台进程切换到后台运行.
需要注意的是,后台进程在另外的终端是查看不到任何信息的,如果需要查看进程的输出信息,一般是将输出重定向到文件中,然后使用 tail 命令实时查看输出.
在 Linux 中,可以使用以下命令将前台进程切换到后台进程:
bg
命令将挂起的进程切换到后台运行。 使用 command & ,这样的方式是一开始就将 command 进程放到后台运行.
我们通过下面这个例子,来感受下前台进程和后台进程是如何切换的.
1、编写 test.py 文件.
import os
import time
def main():
a = 1
while True:
time.sleep(1)
a += 1
print("a---->", a)
if a > 30:
break
if __name__ == '__main__':
main()
2、通过 python test.py 执行程序。然后使用 ctrl + Z 是程序暂停到后台。注意,这个时候程序不会再往下执行了.
如果想程序继续往下执行,使用 bg 命令将其切换到后台运行.
还有一种方式是:在最开始执行命令的时候,加上 & 。即 python main.py & .
python test.py
a----> 2
a----> 3
^Z
[1] + 1761 suspended python test.py
sample_test [master●] %
3、通过 jobs 命令查询后台进程.
sample_test [master●] % jobs
[1] + suspended python test.py
sample_test [master●] %
4、使用 fg 命令将指定的后台进程切换到前台运行。( fg %N ,这里的N是 jobs 返回的序号,并不是进程的PID) 。
sample_test [master●] % fg %1
[1] + 1761 continued python test.py
a----> 4
a----> 5
a----> 6
a----> 7
通过上面的讲解,我们知道了什么是后台进程和前台进程。接下来,我们再讲讲什么是孤儿进程和僵尸进程.
孤儿进程 是指 父进程已经结束或者异常退出,而子进程还在运行的情况下,子进程就会变成孤儿进程 。孤儿进程会被操作系统的 init进程接管 , init进程 会成为孤儿进程的新的父进程,并负责回收孤儿进程的资源,避免资源泄露和浪费.
因此一般来说,孤儿进程并不会有什么危害.
我们来看一个关于孤儿进程的例子:
在main函数中,创建子进程,然后让父进程睡眠1s,让子进程先运行打印出其进程id(pid)以及父进程id(ppid);随后子进程睡眠3s(此时会调度到父进程运行直至结束),目的是让父进程先于子进程结束,让子进程有个孤儿的状态;最后子进程再打印出其进程id(pid)以及父进程id(ppid);观察两次打印 其父进程id(ppid)的区别.
import os
import time
def main():
pid = os.fork() # 创建子进程
if pid < 0:
# 创建失败
print("fork failed!")
exit(1)
elif pid == 0: # 子进程
print("I am the child process.")
print("pid:%d, ppid:%d " % (os.getpid(), os.getppid()))
# 子进程睡眠3s,保证父进程先退出,此后子进程成为孤儿进程
time.sleep(3)
# 注意查看孤儿进程的父进程变化
print("after sleep, pid:%d, ppid:%d" % (os.getpid(), os.getppid()))
assert os.getppid() == 1
print("child process is exited.")
else:
print("I am father process.")
# 为保证子进程先运行,让父进程睡眠1s
time.sleep(1)
print("father process is exited.")
if __name__ == '__main__':
main()
执行结果:
运行结果表明:当父进程结束后,子进程成为了孤儿进程。因为它的父进程id(ppid)变成了1,即init进程成为该子进程的父进程了.
Linux 僵尸进程是指已经结束执行的进程,但是其父进程还没有对其进行处理,导致该进程的进程描述符仍然存在于系统中 ,这种进程被称为 僵尸进程 .
僵尸进程不会占用系统资源,但是如果大量的僵尸进程存在,会占用系统的进程描述符资源,导致系统进程描述符资源耗尽,从而导致系统崩溃.
为了避免僵尸进程的出现,父进程需要及时对其进行处理,可以使用 wait() 或 waitpid() 等系统调用来等待子进程结束并回收其资源。另外,也可以使用信号处理机制,在父进程中注册 SIGCHLD 信号处理函数来处理子进程结束的信号.
关于 僵尸进程的例子 :
在main函数中,创建子进程,然后让父进程睡眠30s,让子进程先终止(注意和孤儿进程例子的区别);这里子进程结束后父进程没有调用wait/waitpid函数获取其状态,用ps查看进程状态可以看出子进程为僵尸状态.
import os
import time
def main():
pid = os.fork() # 创建子进程
if pid < 0:
# 创建失败
print("fork failed!")
exit(1)
elif pid == 0: # 子进程
print("I am the child process.I am exited.")
exit(0)
else:
print("I am father process.")
# 父进程睡眠30s等待子进程退出,且没有调用wait/waitpid获取其状态
# 子进程会成为僵尸进程
time.sleep(30)
print("father process is exited.")
if __name__ == '__main__':
main()
开一个终端,在终端是运行 test.py .
在子进程结束,父进程睡眠(还没退出)的时候,再开一个终端用PS查看进程状态.
注意:
这是每个子进程在结束时都要经过的阶段。
那么如何杀死僵尸进程呢,可以查询 僵尸进程与孤儿进程 链接,来进行学习,这里就不再讲述.
现在再回过头来看 面试题的要求:
在终端中执行 python main.py 命令,启动后台进程来进行业务处理.
那么我们可以利用孤儿进程的特性,完成上面的需求.
1、通过 os.fork() 创建子进程.
2、创建完成后,让父进程退出,子进程继续运行.
简单案例:
import os
import time
def main():
pid = os.fork() # 创建子进程
a = 0
if pid < 0:
# 创建失败
print("fork failed!")
exit(1)
elif pid == 0: # 子进程
for i in range(10):
time.sleep(1)
a += i
print("child process calculate result: %d" % a)
else:
print("I am father process.")
exit(0)
if __name__ == '__main__':
main()
sample_test [master●] % python test.py
I am father process.
10秒钟过后
sample_test [master●] % child process calculate result: 45
参考资料:
僵尸进程与孤儿进程 。
最后此篇关于从一道面试题来学习前台进程和后台进程、孤儿进程和僵尸进程的文章就讲到这里了,如果你想了解更多关于从一道面试题来学习前台进程和后台进程、孤儿进程和僵尸进程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
从 0 开始搭建一套后台管理系统,成本巨大,所以都会选择一套成熟的组件库,基于此,再堆叠业务逻辑。我们公司的组件库基于 Ant Design。Ant Design 包含一套完整的后台解决方案,不仅
在我的 IOS 应用程序中,我有一个标记为 retain 的 NSDate* 属性 当我的应用程序再次激活时,属性值已被释放。 我是否误解了属性和内存管理的工作原理,我该如何防范? 最佳答案 很明显,
我有一个使用 BackgroundWorker 组件的示例 WinForms 应用程序。它工作正常,但是当我点击 Cancel 按钮取消后台线程时,它并没有取消线程。当我点击 Cancel 按钮调用
我目前正在开发一个应用程序,该应用程序在启动时会对服务器执行 ping 操作,该服务器会为每个连接的设备返回一个唯一标识符。设备每 5 秒从服务器检索另一页以获取一组不同的数据。这个唯一的 ID 可以
我正在开发一个应用程序,当它通过主页按钮在后台按下时,计时器应该启动,当应用程序返回前台并且计时器已经过了一定时间时,应该是执行。 我的问题是 当我的应用程序转到背景/前景? 是否有特殊的方法或其他技
我有 map View ,其中几乎没有 MKPointAnnotation。 一切正常,但是, View 的 MKPoiintAnnotation 的“背景”是“不可见的”,因此不是很“可见”。 我想
我在 iOS 中开发广告数据应用程序。我的应用程序广告数据在前台很好。但我想在 ios 后台宣传信标数据。我设置了背景外设设置。和广告数据 advertisingData = [CBAdvertise
如果我有一组操作,我想根据特定条件在后台工作程序中运行,例如,我有 10 个条件 if(a) BackgroundWorker doA = new backgroundworker() if(
我想独立运行一个函数。从我调用的函数中,我想在不等待其他函数结束的情况下返回。 我试过用 threadind,但这会等待,结束。 thread = threading.Thread(target=my
我想在用户在线时立即执行一些任务,即使他在后台也是如此。我正在使用 Reachability 类来检查互联网。但是当我在后台时,这个类没有通知我。我知道有人早些时候问过这个问题,但没有找到任何解决方案
我在后台播放文本转语音时出现间歇性(哎呀!)问题,由 Apple Watch 触发。我已经正确设置了后台模式、AVSession 类别和 WatchKitExtensionRequest 处理程序。
我有一个相当复杂的程序,所以我不会在这里转储整个程序。这是一个简化版本: class Report { private BackgroundWorker worker; public
我有一个任务在 backgroundworker 中运行。单击开始按钮,用户将启动该过程,并获得一个取消按钮来取消处理。 当用户点击取消时,我想显示一个消息框“进程尚未完成,你想继续吗”。 这里我希望
我有一个按以下方式编码的脚本。我想将它作为后台/守护进程运行,但是一旦我启动脚本,如果我关闭它从程序运行的终端窗口终止。我需要做什么来保持程序运行 loop do pid = fork do
我正在制作一个使用 ActivityRecognition API 在后台跟踪用户 Activity 的应用,如果用户在指定时间段(例如 1 小时)内停留在同一个地方,系统就会推送通知告诉用户去散步.
当尝试使用 URLSession 的 dataTaskPublisher 方法发送后台请求时: URLSession(configuration: URLSessionConfiguration.ba
当我编译这段代码时,我得到了他的错误,对象引用设置为null,错误位置在Dowork中,argumenttest.valueone = 8; public partial class Form1 :
有什么方法可以使用最小化或不活动的应用程序吗?我可以打开我的应用程序,然后打开并使用另一个应用程序,然后按一个按钮来激活我的程序吗? 例如,打开我的应用程序,打开 Safari,按下按钮(F1 或任何
我的具体要求是一个在后台运行的应用程序,被通知显示器即将进入休眠状态或者设备已经或即将达到空闲超时 - 然后唤醒并执行一些(简短的)一段代码。 我在这里找到了有关应用程序被置于后台或暂停的通知的引用:
我有一个 LSUIElement 设置为 1 的应用程序。它有一个内置编辑器,因此我希望该应用程序在编辑器打开时出现在 Cmd+Tab 循环中。 -(void)stepIntoForegrou
我是一名优秀的程序员,十分优秀!