进程、线程、协程
进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发;
线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发;
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。从技术的角度来说,“协程就是你可以暂停执行的函数”。
对单核cpu来讲线程不能提高性能,只是提高cpu利用率;
1、当运行为非计算密集型job时,可能穿插着大量的IO调用,IO的一个特性就是阻塞等待,阻塞的时间消耗远大于线程切换的花费。所以利用多线程并发处理问题,切换阻塞等待结束的线程使用cpu可以提高cpu利用率。
2、当运行为计算密集型job时,IO阻塞影响较小,这时使用多线程,适得其反,反而会分走cpu部分性能降低了cpu的计算效率。
多核cpu和多cpu
多个物理CPU,CPU通过总线进行通信,效率比较低。
核CPU,不同的核通过L2 cache进行通信,存储和外设通过总线与CPU通信
进程与线程的关系
1、线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
2、每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
3、在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
4、系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。
线程与协程的关系
1、一个线程可以多个协程,一个进程也可以单独拥有多个协程。
2、线程进程都是同步机制,而协程则是异步。
3、协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
4、线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
5、协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.。
6、线程是协程的资源。协程通过Interceptor来间接使用线程这个资源。
多线程简单应用
多线程施加锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
# -*-* encoding:UTF-8 -*-
# python3
# author : DK
# date : 2022/03/01
import threading
import time
import numpy
# 定义取款机余额
bank_atm = 10000
# # 定义矩阵
# big_mat = numpy.random.rand(10000,10000)
threadLock = threading.Lock()
class Atm_Thread(threading.Thread):
def __init__(self,threadId,name,access_list, sleep_time):
threading.Thread.__init__(self)
self.threadId = threadId
self.name = name
self.sleep_time = sleep_time
self.access_list = access_list
def run(self):
print("开始存取:", self.name)
# 获得锁,成功获得锁定后返回 True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回 False
threadLock.acquire()
access(self.name, self.sleep_time, self.access_list)
# matrix(self.name, self.sleep_time, self.access_list)
# 释放锁
threadLock.release()
def __del__(self):
print(self.name, "线程结束!")
def access(threadName, sleep_time, access_list):
global bank_atm
for i in access_list:
time.sleep(sleep_time)
bank_atm = bank_atm + i
space = " "*(6 - len(str(i)))
if i>=0:
print("[%s] %s 存入ATM %d%s 元,存入后ATM的余额为 %d 元" % (time.ctime(time.time()),threadName,i,space,bank_atm))
else:
print("[%s] %s 取出ATM %d%s 元,取出后ATM的余额为 %d 元" % (time.ctime(time.time()),threadName,i,space,bank_atm))
# def matrix(threadName, sleep_time, times):
# global big_mat
# start = time.time()
# for i in range(times):
# big_mat = big_mat*big_mat
# end = time.time()
# cost = end - start
# print("%s 花费时常约%d"%(threadName, cost))
threads = []
print("创建3个人进行存取款")
for i in range(3):
name = "Thread-" + str(i)
# 创建新线程
thread_person = Atm_Thread(i, name, [100,-100, 500, 10000, -10000],1)
# 开启线程
thread_person.start()
# 添加线程到线程列表
threads.append(thread_person)
# 等待所有线程完成
for t in threads:
t.join()
print("主进程结束!")
|
运行结果:
多线程不施加锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
# -*-* encoding:UTF-8 -*-
# python3
# author : DK
# date : 2022/03/01
import threading
import time
import numpy
# 定义取款机余额
bank_atm = 10000
print("ATM当前余额为 %d 元"%bank_atm)
# # 定义矩阵
# big_mat = numpy.random.rand(10000,10000)
threadLock = threading.Lock()
class Atm_Thread(threading.Thread):
def __init__(self,threadId,name,access_list, sleep_time):
threading.Thread.__init__(self)
self.threadId = threadId
self.name = name
self.sleep_time = sleep_time
self.access_list = access_list
def run(self):
print("创建人员:", self.name)
# 获得锁,成功获得锁定后返回 True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回 False
# threadLock.acquire()
access(self.name, self.sleep_time, self.access_list)
# matrix(self.name, self.sleep_time, self.access_list)
# 释放锁
# threadLock.release()
def __del__(self):
print(self.name, "线程结束!")
def access(threadName, sleep_time, access_list):
global bank_atm
for i in access_list:
time.sleep(sleep_time)
bank_atm = bank_atm + i
space = " "*(6 - len(str(i)))
if i>=0:
print("[%s] %s 存入ATM %d%s 元,存入后ATM的余额为 %d 元" % (time.ctime(time.time()),threadName,i,space,bank_atm))
else:
print("[%s] %s 取出ATM %d%s 元,取出后ATM的余额为 %d 元" % (time.ctime(time.time()),threadName,i,space,bank_atm))
# def matrix(threadName, sleep_time, times):
# global big_mat
# start = time.time()
# for i in range(times):
# big_mat = big_mat*big_mat
# end = time.time()
# cost = end - start
# print("%s 花费时常约%d"%(threadName, cost))
threads = []
print("创建3个人进行存取款")
for i in range(3):
name = "Thread-" + str(i)
# 创建新线程
thread_person = Atm_Thread(i, name, [100,-100, 500, 10000, -10000],1)
# 开启线程
thread_person.start()
# 添加线程到线程列表
threads.append(thread_person)
# 等待所有线程完成
for t in threads:
t.join()
print("主进程结束!")
|
运行结果:
可自行调用matrix函数检测多线程在多核处理器中的运行状况
多进程简单应用
多进程并行(非阻塞)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# -*-* encoding:UTF-8 -*-
# python3
# author : DK
# date : 2022/03/01
#coding: utf-8
import multiprocessing
import time
def func(msg):
print("[%s] 开始休眠 %d 秒"%(time.ctime(time.time()), msg))
time.sleep(msg)
print("[%s] 我休眠了 %d 秒"%(time.ctime(time.time()), msg))
if __name__ == "__main__":
cpu_num = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes = cpu_num)
for i in range(4):
pool.apply_async(func, (i, )) #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
print('开始休眠进程')
pool.close()
pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print('休眠测试结束')
|
运行结果:
多进程并行(阻塞)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# -*-* encoding:UTF-8 -*-
# python3
# author : DK
# date : 2022/03/01
#coding: utf-8
import multiprocessing
import time
def func(msg):
print("[%s] 开始休眠 %d 秒"%(time.ctime(time.time()), msg))
time.sleep(msg)
print("[%s] 我休眠了 %d 秒"%(time.ctime(time.time()), msg))
if __name__ == "__main__":
cpu_num = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes = cpu_num)
for i in range(4):
pool.apply(func, (i, )) #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
print('开始休眠进程')
pool.close()
pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print('休眠测试结束')
|
运行结果:
进程线程与cpu
1、对于多cpu,多个进程可以并行在多个cpu中计算,当然也会存在进程切换;对于单cpu,多个进程在这个单cpu中是并发运行,根据时间片读取上下文+执行程序+保存上下文。同一个进程同一时间段只能在一个cpu中运行,如果进程数小于cpu数,那么未使用的cpu将会空闲。
2、对于多核cpu,进程中的多线程并行执行。对于单核cpu,多线程在单cpu中并发执行,根据时间片切换线程。同一个线程同一时间段只能在一个cpu内核中运行,如果线程数小于cpu内核数,那么将有多余的内核空闲。
参考:
进程