文章目录
线程和进程
1.多任务介绍
1.现实中的多任务
- 看着番剧吃着饭
2.计算机中的多任务
-
计算机中的多任务是指,操作系统同时完成多项任务的处理。此处,同时是指同一个时间段内,而非某个瞬时时间点。
多任务处理是指,用户在同一时间段内运行多个应用程序,每个应用程序就可以称之为一个任务。
现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?
答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。
3.并发与并行
-
并发处理(concurrency Processing):指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机(CPU)上运行,但任一个时刻点上只有一个程序在处理机(CPU)上运行
并行处理(Parallel Processing):是计算机系统中能同时执行两个或更多个处理的一种计算方法。并行处理可同时工作于同一程序的不同方面。并行处理的主要目的是节省大型和复杂问题的解决时间。
并发的关键是你有处理多个任务的能力,不一定要同时。并行的关键是你有同时处理多个任务的能力。所以说,并行是并发的子集
[外链图片转存失败(img-LnsmHe6v-1565179216903)(D:\360安全浏览器下载\Python暑期班\data\QQ图片20190806140144.png)]
demo:
import time
def download_music():
"""模拟下载歌曲,需要5秒钟下载完成"""
for i in range(5):
time.sleep(1) # 休眠1秒
print("-----正在下载歌曲%d----" % i)
def play_music():
"""模拟播放歌曲,需要5秒钟播放完成"""
for i in range(5):
time.sleep(1) # 休眠1秒
print("-----正在播放歌曲%d----" % i)
def main():
# 先下载歌曲
download_music()
# 再播放歌曲
play_music()
if __name__ == '__main__':
main()
2.进程
进程:一个程序的执行实例。每个进程提供执行程序所需的所有资源。
进程本质上是资源的集合。
一个进程有虚拟的地址空间,可执行代码、操作系统的接口、安全的上下文(记录启动该进程的用户和权限等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间),还要至少有一个线程。
进程的创建 — fork()
import os
pid = os.fork()
if pid == 0:
print("Zhejiang University.")
else:
print("City College.")
在Unix/Linux中,提供了fork()系统函数。
- 普通的函数调用,调用一次,返回一次
- fork()调用一次,返回两次。
- 因为操作系统自动把当前的进程(父进程)复制一份(子进程),然后分别在父进程和子进程内返回。
fork()子进程永远返回0,而对应的父进程返回子进程的ID。
一个父进程可以fork出很多子进程。父进程可以记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。
getpid()返回当前进程标识
getppid()返回父进程标识
import os
pid = os.fork()
if pid < 0:
print("fork 调用失败.")
elif pid == 0:
print("我是子进程:\t %s,我的父进程是:\t %s"% (os.getpid(),os.getppid()))
else:
print("我是父进程:\t %s,我的子进程是:\t %s"% (os.getpid(),pid))
print("父子进程都可以执行这里.")
我是父进程: 2274,我的子进程是: 2275
父子进程都可以执行这里.
我是子进程: 2275,我的父进程是: 2274
父子进程都可以执行这里.
3.线程
线程是操作系统能够运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位。
一条线程是进程中一个单一顺序的控制流,一个进程可以并发多个线程,每条线程并行执行不同的任务。
一条线程是一个execution context(执行上下文),即一个CPU执行时所需要的一串指令。
线程的工作方式
假设你正在读一本书,没有读完,你想休息一下,但是你想在回来时恢复到当时读的具体进度。有一个方法就是记下页数、行数与字数这三个数值,这些数值就是execution context。如果你的室友在你休息的时候,使用相同的方法读这本书。你和她只需要这三个数字记下来就可以在交替的时间共同阅读这本书了。
线程的工作方式与此类似。CPU会给你一个在同一时间能够做多个运算的幻觉,实际上它在每个运算上只花了极少的时间,本质上CPU同一时刻只干了一件事。它能这样做就是因为它有每个运算的execution context。就像你能够和你朋友共享同一本书一样,多任务也能共享同一块CPU。
进程与线程的区别
-
同一进程中的线程共享同一内存空间,但是进程之间是独立的。
-
同一个进程中的所有线程的数据共享,但进程之间的数据是独立的。
-
对主线程的修改可能影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
-
线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。
-
同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。
-
创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。
-
一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
-
线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。
Python中多线程的实现
- 1.创建一个函数传入Thread对象中
import threading
import time
def download_music():
"""模拟下载歌曲,需要5秒钟下载完成"""
for i in range(5):
time.sleep(1) # 休眠1秒
print("-----正在下载歌曲%d----" % i)
def play_music():
"""模拟播放歌曲,需要5秒钟播放完成"""
for i in range(