Linux进程管理之子进程的创建(fork函数)、子进程与线程的区别、fork函数的简单使用例子、子进程的典型应用场景、父进程等待子进程结束后自己再结束
收尾
进程终止:子进程通过exit()或_exit()终止,父进程通过wait()或waitpid()等待子进程终止,并获取其退出状态。?其实可以考虑在另一篇博文中来写
fork函数讲解
fork函数概述
fork() 是 Linux 中用于创建新进程的系统调用。当一个进程调用 fork() 时,系统会创建一个与原进程几乎完全相同的子进程。
新的子进程在有相关写操作时,会复制父进程的资源(即写时复制的概念)。
父进程的PID和子进程的PID是不同的。
父进程和子进程会从 fork() 调用的返回值处开始继续执行,但返回值在父进程和子进程中是不同的。
fork函数的工作原理和流程
其具体工作原理和流程如下:
当某个进程调用fork() 创建子进程后,系统会创建一个与原进程几乎完全相同的子进程,然后父进程和子进程会从fork()返回的地方继续执行。
不过两个进程得到的fork()的返回值不一样:
- 对于父进程,它得到的
fork()的返回值是子进程PID; - 对于子进程,它得到的
fork()的返回值是0;
即:
如果 fork() 成功,它会返回两次:在父进程中返回子进程的 PID,在子进程中返回 0。
如果 fork() 失败(如资源不足),返回 -1,并设置 errno 以说明错误。
子进程的特点
- 父子进程的几乎相同:子进程是父进程的副本,它们俩几平是相同的,除了
fork()的返回值和 PID。 - 资源复制:父子进程共享文件描述符、内存映射等资源,但会使用“写时复制”(Copy-On-Write, COW)技术优化内存使用。这意味着在父子进程开始执行时,内存不会立即复制,而是在修改内存时才复制。
- 进程独立性:父进程和子进程是独立的,执行过程中互不影响,但它们会共享某些资源(如打开的文件)。
进程与线程的区别
fork() 创建的子进程在某些方面与线程(特别是线程的创建和管理)有相似之处,但它们在操作系统级别的实现和资源管理上有一些关键的区别。
- 进程(Process)
- 进程是操作系统分配资源的基本单位。每个进程都有独立的地址空间、文件描述符、栈、堆等资源。
- 进程之间是独立的,它们不会共享内存空间(除非显式使用共享内存或其他进程间通信机制),每个进程有自己的 PID 和独立的资源。
- 进程的创建(通过
fork())是相对重的操作,需要操作系统为子进程分配新的资源(如内存)。
- 线程(Thread)
- 线程是进程内部的执行单元,同一个进程中的多个线程共享进程的资源(如内存、文件描述符等),它们共享相同的地址空间。
- 线程之间是轻量级的,因为它们共享进程的资源,而不需要像进程那样拥有完全独立的资源。
- 线程的创建通常比进程轻量,操作系统管理线程的开销较小,线程之间可以很容易地进行共享数据和通信(如使用互斥锁、条件变量等)。
二者的关键差异
-
地址空间和资源:
- 进程:子进程有独立的地址空间。父进程与子进程之间没有直接共享内存,除非使用共享内存(
mmap())或其他进程间通信(IPC)方式。 - 线程:线程在同一进程内共享内存、文件描述符等资源。线程间的通信非常高效,因为它们共享相同的地址空间。
- 进程:子进程有独立的地址空间。父进程与子进程之间没有直接共享内存,除非使用共享内存(
-
创建开销:
- 进程:通过
fork()创建子进程时,操作系统需要为新进程分配独立的资源(如内存空间)。这使得进程创建的开销相对较大。 - 线程:创建线程时,操作系统只需要分配线程控制块(TCB)等较小的资源,不需要分配独立的内存空间,因此线程创建比进程轻量。
- 进程:通过
-
执行独立性:
- 进程:父进程与子进程相互独立,父进程的退出不会影响子进程,反之亦然。它们各自拥有独立的控制流。
- 线程:同一进程中的多个线程共享控制流,互相协作。线程的退出会影响到进程的状态,甚至可能导致整个进程退出。
-
调度和切换:
- 进程:操作系统调度时,进程之间的切换需要保存和恢复更多的状态,因为每个进程有独立的地址空间。
- 线程:线程之间的切换较轻量,操作系统只需要保存和恢复少量状态(如寄存器、栈指针等),因为线程共享地址空间。
fork() 创建的子线程和线程的相似性和差异
相似性:
- 并行执行:无论是
fork()创建的子进程还是线程,它们都可以并行执行(多核 CPU 上); - 并发性:父进程与子进程之间的调度是并发的,线程间的调度也是如此。
差异:
- 资源分配:
fork()创建的子进程拥有独立的资源(如地址空间、PID),而线程共享进程的资源。 - 进程控制:父进程与子进程是完全独立的,退出父进程不会直接影响子进程;线程则不同,进程退出时会导致所有线程结束。
何时选择使用进程,何时使用线程?
- 如果需要完全隔离的执行环境,或者需要实现进程间的严格隔离,应该选择进程(使用
fork())。例如,fork()在服务器中常用于创建多个独立的工作进程,每个进程可以处理独立的任务。 - 如果需要多个轻量级的并发任务,并且共享资源是必须的,应该选择线程。线程通常适用于需要大量并发操作且共享内存的场景,例如 Web 服务器的请求处理。
小结
虽然子进程和线程在某些方面表现得有点相似——例如它们可以并行执行,但它们本质上是不同的:子进程具有独立的资源和地址空间,而线程则是共享同一进程的资源。fork() 创建的子进程是“重型”的,而线程则是“轻型”的。因此,子进程和线程虽然在并发执行上有相似之处,但它们的实现和适用场景有很大区别。
fork函数使用的简单例子
下面是一个简单的示例,展示如何使用 fork() 创建一个子进程:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() {pid_t pid = fork(); // 创建新进程if (pid == -1) {// 错误处理:fork()失败perror("fork failed");return 1;} else if (pid > 0) {// 父进程printf("This is the parent process, PID: %d, child PID: %d\n", getpid(), pid);sleep(2); // 父进程睡眠 2 秒,确保子进程有时间执行,否则有可能出现子进程还没执行完父进程就执行完的情况} else {// 子进程printf("This is the child process, PID: %d, parent PID: %d\n", getpid(), getppid());}return 0;
}
代码解释:
当 fork() 被调用时,操作系统会在内核中创建一个新进程,子进程会复制父进程的大部分资源(包括内存、文件描述符等)。然后父进程和子进程都会从 fork() 语句的下一行代码开始继续执行,但它们的执行路径有所不同:
- 父进程:父进程得到的
fork()返回值是子进程的 PID(大于 0 的值),父进程会执行属于它的if条件分支代码块。 - 子进程:子进程得到的
fork()返回值的值是 0,子进程会执行属于它的if分支条件代码块。
由于父进程和子进程得到的fork() 的返回值不一样,即各自的pid变量的值不一样,所以在后续的代码中各自执行了不同的条件分支。
在Linux开发板上测试上面这个例子
代码文件复制到Ubuntu中

交叉编译
运行下面的命令进行交叉编译
cd /home/book/mycode/C0034_fork
arm-buildroot-linux-gnueabihf-gcc -o fort_test fort_test.c

复制到NFS目录中,备用。

在开发板上测试
打开串口终端→打开开发板→挂载网络文件系统
执行下面的代码运行测试程序
/mnt/fork_test/fort_test
运行结果如下:

可见,符合我们的预期,所以测试成功。
子进程的应用场景
子进程的创建通常是为了实现进程间的隔离、并行化或者并发处理,以及提升程序的响应性和资源管理。虽然有时线程可能更合适,但子进程在某些场景下非常重要。下面我将列举一些典型的子进程应用场景,帮助你更好地理解它们的使用场景。
注意:要理解下面的应用场景关键要明白子进程与父进程为何能执行不同的代码,其实在实际代码中就是通过判断fork的返回值来进行的,通过前面的例子我们已经知道fork()函数对父进程和子进程的返回值不一样嘛。
1. 服务器模型中的进程池
- 场景:Web 服务器(如 Apache)或数据库服务器常常需要处理大量并发请求。这时,创建一个子进程来处理每一个请求,可以保证每个请求都在独立的进程中运行,互不干扰。
- 原因:使用子进程可以实现进程间隔离,每个请求都在独立的进程中执行,即使其中一个请求出现崩溃或问题,也不会影响其他请求。父进程只负责接收和分发任务,而实际处理任务的工作交给多个子进程。
- 举例:
- Web 服务器:比如 Apache 使用子进程处理不同的客户端请求,这样即使一个子进程崩溃,其他请求仍然能继续处理。
- 数据库服务:一些数据库管理系统通过子进程处理不同的查询,确保查询之间不会互相干扰。
2. 任务调度与并行处理
- 场景:当某个程序需要同时进行多个独立的计算任务时,创建子进程可以将这些任务分配给不同的进程,使它们并行执行,从而提高执行效率。
- 原因:多核 CPU 环境下,父进程可以通过
fork()创建多个子进程,这样每个子进程都可以在不同的 CPU 核心上并行执行任务,从而提高计算效率。 - 举例:
- 科学计算:例如,处理大规模数据分析时,可以将数据分成多个块,每个子进程处理一个数据块,最后将结果合并。
- 视频处理:在进行视频转码或图片渲染时,创建多个子进程来并行处理不同帧或不同部分的图像。
3. 资源隔离与安全性
- 场景:一些需要高安全性的应用会将不同的功能模块分离成不同的进程,这样即使某个进程被攻击或崩溃,其他进程的运行不会受到影响。
- 原因:子进程的隔离性使得每个进程拥有自己的内存空间和资源,避免了进程间的干扰。这对于处理敏感信息或者确保系统稳定性和安全性至关重要。
- 举例:
- 浏览器:现代浏览器会为每个标签页、插件或扩展创建不同的进程,这样一个标签页崩溃不会导致整个浏览器崩溃。
- 操作系统安全:如一些操作系统使用子进程来执行高权限操作,避免给系统带来潜在风险。
4. 守护进程(Daemon)
- 场景:守护进程是一种长期在后台运行的进程,通常在系统启动时启动,并在系统关闭时停止。守护进程需要创建一个子进程来执行具体的工作。
- 原因:守护进程通常不与用户直接交互,它们负责监视某些任务或提供某些服务。通过创建子进程,守护进程可以独立处理各种工作,保持系统的高效和稳定。
- 举例:
- 系统守护进程:例如
cron进程定期运行任务,sshd进程监听远程连接。 - 文件服务器:一个守护进程可以监听文件的变化并对文件进行同步或备份。
- 系统守护进程:例如
5. 进程控制与协作
- 场景:父进程与子进程之间的协作。父进程创建子进程后,可以与子进程进行通信,通过管道、消息队列等机制协作完成任务。
- 原因:父子进程之间可以通过进程间通信(IPC)进行数据传递,子进程执行任务的结果会影响父进程的执行。父进程和子进程之间的关系通常是控制与执行的关系。
- 举例:
- 编译工具:在某些构建系统(如
make)中,父进程通过创建子进程来执行不同的编译任务,最后将结果汇总。 - 日志管理:父进程可以创建多个子进程来处理日志文件,每个子进程独立地处理不同的日志任务,最后通过 IPC 汇总结果。
- 编译工具:在某些构建系统(如
6. 多重任务并发处理
- 场景:当一个应用程序需要并发执行多个不同的任务时,可以通过
fork()创建多个子进程,分配任务给不同的子进程。 - 原因:这种方式适合处理需要大量并行工作的任务,例如并行搜索、并行计算等。
- 举例:
- 多线程下载管理器:如果一个文件很大,可以通过
fork()创建多个子进程并行下载文件的不同部分,最后合并成一个完整的文件。 - 分布式计算:某些分布式计算任务会将计算工作分配给多个进程来并行处理,提高整体计算速度。
- 多线程下载管理器:如果一个文件很大,可以通过
7.小结
子进程通常用于以下几种情况:
- 进程隔离和独立执行:避免不同任务间的干扰,提高系统稳定性。
- 并行化计算:充分利用多核 CPU 提高计算效率。
- 长期运行的守护进程:独立执行后台任务。
- 提高安全性:隔离不同的任务和数据,防止安全问题扩散。
子进程的优势通常体现在资源隔离和任务并行化上,尤其在需要并发处理多个独立任务或确保系统高可靠性和稳定性时,使用子进程可以大大提高系统性能和安全性。
父进程等待子进程结束后自己再结束
原因分析
当 fork() 创建子进程后,子进程是独立的进程,和父进程共享部分资源,但运行是相互独立的。
如果父进程提前结束,子进程仍然可以继续执行,直到它自己终止或被系统杀死。
如果父进程退出,而子进程仍在运行,那么子进程会成为孤儿进程。
孤儿进程会被 init 进程(PID=1) 领养,init 进程会负责等待它结束,回收它的资源。
但通常我们还是会让父进程等待子进程结束后自己再结束,原因如下:
1. 防止子进程变成僵尸进程(Zombie Process)
- 问题:
- 当子进程结束时,它的退出状态信息会保留在系统的进程表中,直到父进程使用
wait()或waitpid()读取该信息。 - 如果父进程没有处理这个信息,子进程的进程表项不会被释放,导致僵尸进程(Zombie Process)。
- 如果系统中存在大量僵尸进程,会占用进程表,可能导致新进程无法创建。
- 当子进程结束时,它的退出状态信息会保留在系统的进程表中,直到父进程使用
2. 确保父进程在子进程完成任务后再退出
- 有时候子进程的任务和父进程相关,比如:
- 子进程负责处理数据,父进程等待结果。
- 子进程执行重要任务,父进程需要等它完成才能继续。
3. 避免创建大量孤儿进程
- 虽然孤儿进程会被
init进程接管,但不是所有情况下都希望这样:- 如果有多个子进程,可能会导致 进程管理变得混乱。
- 如果子进程运行时间较长,可能会造成 不必要的资源占用。
- 更好的方法:
- 直接让父进程
wait()等待子进程。 - 或者 让子进程调用
setsid()使自己变成独立的进程组。
- 直接让父进程
4. 让父进程控制子进程的执行
- 例如:
- 父进程动态分配任务给子进程。
- 父进程需要获取子进程的退出状态来决定下一步操作。
5 最佳实践
- 如果子进程需要完成某些任务,父进程应该
wait()等待,避免进程管理混乱。 - 如果不关心子进程的状态,但不想产生僵尸进程,可以用
SIGCHLD信号处理:
这样,子进程退出后,系统会自动回收它们的资源。signal(SIGCHLD, SIG_IGN);
使用wait让父进程等待子进程的示例代码
下面是一个简单的 C 代码示例,演示 Linux 父进程如何等待子进程终止:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid = fork(); // 创建子进程if (pid < 0) {perror("fork failed");exit(1);} else if (pid == 0) {// 子进程执行的代码printf("Child process (PID: %d) is running...\n", getpid());sleep(2); // 模拟子进程执行任务printf("Child process (PID: %d) is exiting...\n", getpid());exit(0);} else {// 父进程执行的代码printf("Parent process (PID: %d) is waiting for child (PID: %d)...\n", getpid(), pid);int status;waitpid(pid, &status, 0); // 等待子进程结束if (WIFEXITED(status)) {printf("Child process exited with status %d\n", WEXITSTATUS(status));}printf("Parent process is exiting...\n");}return 0;
}
代码说明:
fork()创建一个子进程,返回两次:- 在父进程中返回子进程的 PID。
- 在子进程中返回 0。
- 子进程执行自己的任务,
sleep(2)模拟耗时操作,然后退出。 - 父进程调用
waitpid()等待子进程结束,并获取其退出状态。 WIFEXITED(status)判断子进程是否正常退出,WEXITSTATUS(status)获取其退出码。
相关文章:
Linux进程管理之子进程的创建(fork函数)、子进程与线程的区别、fork函数的简单使用例子、子进程的典型应用场景、父进程等待子进程结束后自己再结束
收尾 进程终止:子进程通过exit()或_exit()终止,父进程通过wait()或waitpid()等待子进程终止,并获取其退出状态。?其实可以考虑在另一篇博文中来写 fork函数讲解 fork函数概述 fork() 是 Linux 中用于创建新进程的系统调用。当…...
妙用《甄嬛传》中的选妃来记忆概率论中的乘法公式
强烈推荐最近在看的不错的B站概率论课程 《概率统计》正课,零废话,超精讲!【孔祥仁】 《概率统计》正课,零废话,超精讲!【孔祥仁】_哔哩哔哩_bilibili 其中概率论中的乘法公式,老师用了《甄嬛传…...
虚幻基础:UI
文章目录 控件蓝图可以装载其他控件蓝图可以安装其他蓝图接口 填充:相对于父组件填充水平框尺寸—填充—0.5:改变填充的尺寸填充—0.5:改变与父组件的距离 锚点:相对于父组件的控件坐标系原点,屏幕比例改变时ÿ…...
【MySQL篇】事务管理,事务的特性及深入理解隔离级别
目录 一,什么是事务 二,事务的版本支持 三,事务的提交方式 四,事务常见操作方式 五,隔离级别 1,理解隔离性 2,查看与设置隔离级别 3,读未提交(read uncommitted&a…...
项目实战-角色列表
抄上一次写过的代码: import React, { useState, useEffect } from "react"; import axios from axios; import { Button, Table, Modal } from antd; import { BarsOutlined, DeleteOutlined, ExclamationCircleOutlined } from ant-design/icons;const…...
fetch`的语法规则及常见用法
fetch() 是 JavaScript 用于发送 HTTP 请求的内置 API,功能强大,语法简洁。以下是 fetch 的语法规则及常见用法。 1. fetch 基本语法 fetch(url, options).then(response > response.json()) // 解析 JSON 响应体.then(data > console.log(data))…...
如何排查java程序的宕机和oom?如何解决宕机和oom?
排查oom 用jmap生成我们的堆空间的快照Heap Dump(堆转储文件),来分析我们的内存占用 用可视化工具,例如java中的jhat分析Heap Dump文件 ,它分析完会通过一个浏览器打开一个可视化页面展示分析结果 根据oom的类型来调…...
26_ajax
目录 了解 接口 前后端交互 一、安装服务器环境 nodejs ajax发起请求 渲染响应结果 get方式传递参数 post方式传递参数 封装ajax_上 封装ajax下 了解 清楚前后端交互就可以写一些后端代码了。小项目 现在写项目开发的时候都是前后端分离 之前都没有前端这个东西&a…...
代理模式(Proxy Pattern)实现与对比
代理模式(Proxy Pattern)实现与对比 1. 虚拟代理(Virtual Proxy) 定义:延迟加载对象,避免资源浪费。 适用场景:大文件或资源的加载(如图片、数据库连接)。 代码示例 /…...
MySQL - 数据库基础操作
SQL语句 结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。 分类 DDL 数据定义语言(Data Definition Language),定义对数据库对象(库、表、列、索引)的操作。 DML 数据操作语言(Data Manip…...
Spring Boot热部署插件
在实际开发中,我们修改某些代码或页面都需要重启应用后才能生效,如果每次都手动重启,会降低了开发效率;热部署是指当我们修改代码后,服务能自动重启加载新修改的内容,这样大大提高了我们开发的效率…...
pip install cryptacular卡住,卡在downloading阶段
笔者安装pip install cryptacular卡在downloading阶段,但不知道为何 Collecting cryptacularCreated temporary directory: /tmp/pip-unpack-qfbl8f08http://10.170.22.41:8082 "GET http://repo.huaweicloud.com/repository/pypi/packages/42/69/34d478310d6…...
AI大模型从0到1记录学习 day09
第 8 章 面向对象之类和对象 8.1 面向过程和面向对象 面向过程编程(Procedural Programming)和面向对象编程(OOP)是两种不同的编程范式,它们在软件开发中都有广泛的应用。 Python是一种混合型的语言,既支持…...
【FW】ADB指令分类速查清单
1. 设备管理 指令核心作用adb devices列出已连接设备adb reboot重启设备adb reboot bootloader进入Bootloader模式adb reboot recovery进入Recovery模式adb root获取Root权限(需设备支持)adb remount挂载系统分区为可读写 2. 应用管理 指令核心作用adb…...
Kafka中的消息是如何存储的?
大家好,我是锋哥。今天分享关于【Kafka中的消息是如何存储的?】面试题。希望对大家有帮助; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Kafka 中,消息是通过 日志(Log) 的方式进行存储的。…...
Altium Designer——同时更改多个元素的属性(名称、网络标签、字符串标识)
右键要更改的其中一个对象,选择查找相似… 进入到筛选界面,就是选择你要多选的对象的共同特点(名字、大小等等),我这里要更改的是网络标签,所以我选择Text设置为一样。 点击应用就是应用该筛选调节&#…...
当模板方法模式遇上工厂模式:一道优雅的烹饪架构设计
当模板方法模式遇上工厂模式:一道优雅的烹饪架构设计 模式交响曲的实现模板方法模式搭建烹饪骨架(抽象类)具体菜品(子类) 工厂模式 模式协作的优势呈现扩展性演示运行时流程控制 完整代码 如果在学习 设计模式的过程中…...
c++位运算总结
在C中,位运算是对二进制位进行操作的运算,主要有以下几种: 1. 按位与( & ):两个操作数对应位都为1时,结果位才为1,否则为0。例如 3 & 5 , 3 二进制是 0000 0011…...
企业级知识库建设:自建与开源产品集成的全景解析 —— 产品经理、CTO 与 CDO 的深度对话
文章目录 一、引言二、主流产品与方案对比表三、自建方案 vs. 开源产品集成:技术路径对比3.1 自建方案3.2 开源产品集成方案 四、结论与个人观点 一、引言 在当今数据驱动的商业环境中,构建高质量的知识库已成为企业数字化转型的关键一环。本博客分别从…...
Python小练习系列 Vol.6:单词搜索(网格回溯)
🧠 Python小练习系列 Vol.6:单词搜索(网格回溯) 🔍 本期我们来挑战一道 LeetCode 上经典的网格型回溯题 —— 单词搜索,考察对 DFS 状态恢复的掌握! 🧩 一、题目描述 给定一个 m x…...
shell脚本--MySQL简单调用
实现功能 增 数据库的创建,数据表的创建已经实现 创建用户 删 删除数据库, 删除库下的某个表, 删除某个用户 改 暂无 查 查看所有的数据库, 查看某个库下的所有数据表, 查看某个表的结构, 查…...
vue3项目配置别名
vue3项目配置别名 src别名的配置TypeScript 编译配置如果出现/别名引入报找不到的问题 src别名的配置 在开发项目的时候文件与文件关系可能很复杂,因此我们需要给src文件夹配置一个别名!!! // vite.config.ts import {defineCon…...
Rust 面向对象
Rust 面向对象 引言 Rust 是一种系统编程语言,以其高性能、内存安全和并发支持而受到关注。Rust 的面向对象特性是其强大功能之一,它允许开发者以面向对象的方式构建复杂的应用程序。本文将深入探讨 Rust 的面向对象编程(OOP)特性,包括类的定义、继承、封装和多态等概念…...
[ C语言 ] | 从0到1?
目录 认识计算机语言 C语言 工欲善其事必先利其器 第一个C语言代码 这一些列 [ C语言 ] ,就来分享一下 C语言 相关的知识点~ 认识计算机语言 我们说到计算机语言,语言,就是用来沟通的工具,计算机语言呢?就是我们…...
[Mac]利用Hexo+Github Pages搭建个人博客
由于我这台Mac基本没啥环境,因此需要从零开始配置,供各位参考。 注意⚠️:MacBook (M4)使用/bin/zsh作为默认Shell,其对应的配置文件为~/.zshrc 参考文档: HEXO系列教程 | 使用GitHub部署静态博客HEXO | 小白向教程 文…...
pycharm与python版本
python 3.6-3.9 pycharm 2021版本搭配最好 python 3.8 pycharm 2019版本搭配最好 pycharm各版本下载...
Qt在IMX6ULL嵌入式系统中图片加载问题排查与解决
Qt在IMX6ULL嵌入式系统中图片加载问题排查与解决(保姆级教学!) 在使用Qt开发IMX6ULL嵌入式系统的过程中,我遇到了图片加载的常见问题。本文将分享问题排查的详细过程和解决方案,希望能帮助遇到类似困难的开发者。 问题…...
界面控件Telerik和Kendo UI 2025 Q1亮点——AI集成与数据可视化
Telerik DevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库,加快开发速度。Telerik DevCraft提供完整的工具箱,用于构建现代和面向未来的业务应用程序,目前提供UI for ASP.NET MVC、Kendo…...
pycharm终端操作远程服务器
pycharm项目已经连接了远程服务器,但是打开终端,却依旧显示的是本地的那个环境,也就是说没有操作远程的那个环境。只能再使用Xshell去操作远程环境,很麻烦,找了下教程。 来源:https://blog.csdn.net/maolim…...
接口测试中数据库验证,怎么解决?
在接口测试中,通常需要在接口调用前后查询数据库,以验证接口操作是否正确影响了数据库状态。这可以通过数据库断言来实现,PyMySQL库常用于连接和操作MySQL数据库。通过该库,可以在测试中执行SQL语句,查询或修改数据…...
