操作系统的一些“常识”
线程 与 协程 的区别
- 线程:
-
线程是操作系统级别的单位,每个线程有自己的堆栈和指令指针,操作系统负责调度和切换线程。
-
线程的切换通常需要耗费较多的上下文切换时间,因为它涉及到保存和恢复线程的状态(比如寄存器、程序计数器等)。
2.协程:
-
协程则是轻量级的线程,它通常由用户级库或框架进行调度,而不是由操作系统直接控制。
-
协程的切换更加轻量,因为它不需要操作系统介入。协程通常通过挂起(暂停)和恢复(继续执行)来避免一些昂贵的操作。
-
协程可以在遇到 I/O 操作、等待、或者定时任务时自动挂起,然后将CPU资源交给其他任务,而无需操作系统进行线程调度。这就使得协程相对于线程更高效,特别是在需要大量并发而每个任务不需要太多计算资源时。
协程节省调度的原理:
协程与线程最大的区别就在于协程通常由用户级别的调度来管理,而不是操作系统。这种方式带来了几个优势:
-
减少上下文切换的开销:线程切换通常涉及到保存和恢复上下文,协程通过在用户空间完成切换,不需要操作系统介入,因此效率更高。
-
避免了操作系统调度的复杂性:线程的调度是由操作系统负责的,而协程是由程序内部管理的,避免了线程在操作系统调度时的复杂度。
总结:
-
线程:由操作系统管理,进行上下文切换时比较昂贵,需要操作系统保存和恢复状态。
-
协程:轻量级,通常由程序控制,不涉及操作系统的调度,节省了上下文切换的开销,适用于大量并发且任务较轻的场景。
所以,协程的优势在于通过避免频繁的操作系统级别调度和上下文切换,极大提高了效率,尤其适合 I/O 密集型任务。
对于并发编程
主要关注点:
-
如何设计并发和异步任务: 你应该关注如何合理地分配任务,确保任务之间的依赖关系和协作。
-
任务的错误处理和回调: 要确保任务完成时能正确处理结果或错误。
-
性能调优: 在某些特定情况下(如高并发、长时间运行的服务),你可能需要优化任务的调度策略或资源管理(如内存、CPU、I/O 限制等)。但这通常是通过使用适当的并发模型、选择合适的任务调度框架等方式来完成,而不是手动管理任务的完成状态。
静态链接 vs 动态链接
目标文件(.o 编译过的二进制代码)
应用程序中的静态库(.a)—— 被代码或工具中定义它编译时要用到,找到标记,嵌入编译的.o 文件,最终可执行代码。略快(直接跳转)
特点:
-
独立运行:一旦生成了可执行文件,就不再需要原来的 .a 文件了。你可以把程序发给别人,即使他电脑上没有这个库也能运行。
-
可执行文件大:因为库代码被完整地复制进了程序,所以可执行文件的体积会比动态链接大。
-
更新困难:如果 libsdk.a 修复了一个漏洞,你必须重新编译链接你的程序才能应用这个修复。
动态库(Linux 中.so / Windows 中.dll) —— 运行时动态加载,体积小,面向进程共享。略慢(需解析地址,但通常可忽略)
特点:
-
要带库文件:操作系统中动态链接器(如 Linux 的 ld.so),代码或工具中定义,打标记,将程序和库里的函数地址“对接”上然后开始正式运行
-
可执行文件小:多个程序运行同一个库时,内存里只存一份代码
-
更新直接替换库文件即可:“模块化”,根据需要