
并行:在一段时间内真正的同时一起执行多个任务。
对于多核cpu处理多任务,操作系统会给cpu的每个内核安排一个执行的任务,多个内核是真正的一起同时执行多个任务。这里需要注意多核cpu是并行的执行多任务,始终有多个任务一起执行。

- 一个程序运行后至少有一个进程


import multiprocessing
进程对象 = multiprocessing.Process()
进程对象.start()
进程对象 = multiprocessing.Process(target=任务名)
| 参数名 | 说明 |
|---|---|
| target | 执行的目标任务名,这里指的是函数名(方法名) |
| name | 进程名,一般不用设置 |
| group | 进程组,目前只能使用None |
# 导入进程模块
import multiprocessing
import time
# 编写代码
def coding():
for i in range(3):
print("coding...")
time.sleep(0.2)
# 听音乐
def music():
for i in range(3):
print("music...")
time.sleep(0.2)
if __name__ == '__main__':
# 通过进程类创建进程对象
coding_process = multiprocessing.Process(target=coding)
# 通过进程类创建进程对象
music_process = multiprocessing.Process(target=music)
# 启动进程
coding_process.start()
music_process.start()
进程执行带有参数的任务传参有两种方式:
| 参数名 | 说明 |
|---|---|
| args | 以元组的方式给执行任务传参 |
| kwargs | 以字典方式给执行任务传参 |
# 导入进程模块
import multiprocessing
import time
# 编写代码
def coding(num, name):
for i in range(num):
print(name)
print("coding...")
time.sleep(0.2)
# 听音乐
def music(count):
for i in range(count):
print("music...")
time.sleep(0.2)
if __name__ == '__main__':
# 通过进程类创建进程对象
coding_process = multiprocessing.Process(target=coding, args=(3, "传智"))
# 通过进程类创建进程对象
music_process = multiprocessing.Process(target=music, kwargs={"count": 2})
# 启动进程
coding_process.start()
music_process.start()
os.getpid()os.getppid()import os
pid = os.getpid()
print(pid)
# 或者
import multiprocessing
pid = multiprocessing.current_process().pid
print(pid)
def work() :
# 查看当前进程
current.process= multiprocessing.currentprocess()
# 获取父进程的编号
print(“work父进程的编号:”, os.getppid())
os.kill() 方法用于向指定的进程发送信号。有两个参数:pid 和 signal。
pid:要发送信号的进程的进程ID(PID)。signal:要发送的信号的编号或常量。常见的一些信号编号或常量包括:
signal.SIGTERM:终止进程的请求信号(默认)。signal.SIGKILL:强制终止进程的信号。signal.SIGINT:中断进程的信号(通常由键盘上的Ctrl+C触发)。signal.SIGSTOP:暂停进程的信号。要使用 os.kill() 方法,你需要导入 os 和 signal 模块:
import os
import signal
以下是一个使用 os.kill() 方法终止进程的示例:
import os
import signal
# 获取进程ID
pid = 12345 # 替换为想杀死的进程的真实PID
# 发送终止信号以终止进程
os.kill(pid, signal.SIGTERM)
- 请注意,
os.kill()方法只能用来发送信号给同一用户下的进程。如果要终止不属于当前用户的进程,需要具有适当的权限。- 在 Windows 系统上,
os.kill()方法只能终止由 Python 启动的子进程,对于其他进程,你可以使用taskkill命令来终止进程。
在 Python 中,进程之间的全局变量默认是不共享的。这是因为进程是独立的执行单元,拥有自己的内存空间。
实际上创建一个进程就是把主进程的资源进行拷贝产生了一个新的进程,这里主进程和子进程是相互独立的.
由于进程之间拥有独立的内存空间,它们无法直接共享全局变量。因此,在写入数据的进程中修改 my_list,但在读取数据的进程中无法访问到修改后的值。

import multiprocessing
import time
# 全局变量
my_list = []
# 写入数据
def write_data():
for i in range(3):
my_list.append(i)
print("add:", i)
print("write_data", my_list)
# 读取数据
def read_data():
print("read_data", my_list)
if __name__ == '__main__':
# 创建写入数据进程
write_process = multiprocessing.Process(target=write_data)
# 创建读取数据进程
read_process = multiprocessing.Process(target=read_data)
# 启动进程执行相应任务
write_process.start()
time.sleep(1)
read_process.start()
add: 0
add: 1
add: 2
write_data [0, 1, 2]
read_data []
multiprocessing 模块提供的进程间通信机制。import multiprocessing
import time
# 创建队列
my_queue = multiprocessing.Queue()
# 写入数据
def write_data(queue):
for i in range(3):
queue.put(i)
print("add:", i)
print("write_data", list(queue.queue))
# 读取数据
def read_data(queue):
print("read_data", list(queue.queue))
if __name__ == '__main__':
# 创建写入数据进程
write_process = multiprocessing.Process(target=write_data, args=(my_queue,))
# 创建读取数据进程
read_process = multiprocessing.Process(target=read_data, args=(my_queue,))
# 启动进程执行相应任务
write_process.start()
time.sleep(1)
read_process.start()
import multiprocessing
import time
# 工作函数
def work():
for i in range(10):
print("工作中...")
time.sleep(0.2)
if __name__ == '__main__':
# 创建子进程
work_process = multiprocessing.Process(target=work)
# 启动子进程
work_process.start()
# 使用 join() 方法等待子进程完成
work_process.join()
# 延时1秒
time.sleep(1)
print("主进程执行完毕")
import multiprocessing
import time
def work():
while True:
print("工作中...")
time.sleep(0.2)
if __name__ == '__main__':
# 创建子进程
work_process = multiprocessing.Process(target=work)
# 设置为守护进程
work_process.daemon = True
# 启动子进程
work_process.start()
# 主进程暂停1秒
time.sleep(1)
print("主进程执行完毕")
import multiprocessing
import time
def work():
while True:
print("工作中...")
time.sleep(0.2)
if __name__ == '__main__':
work_process = multiprocessing.Process(target=work)
work_process.daemon = False # 这里可以是 False 或 True,都不影响 terminate() 的效果
work_process.start()
time.sleep(1) # 主进程暂停1秒
# 强制结束子进程
work_process.terminate()
print("主进程执行完毕")

import threading
线程对象 = threading.Thread(target=任务名)
线程对象.start()
import threading
def worker(num):
"""线程执行的目标函数"""
print(f"Worker: {num}")
# 创建线程对象
t = threading.Thread(target=worker, args=(10,), kwargs={"key": "value"}, name="MyThread", daemon=True)
# 启动线程
t.start()
threading.Thread 方法的主要参数及其描述:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| target | 可选 | None | 指定线程要执行的函数 |
| args | 可选 | () | 传递给目标函数的参数,以元组形式 |
| kwargs | 可选 | {} | 传递给目标函数的关键字参数,以字典形式 |
| name | 可选 | None | 线程的名称,用于标识和调试 |
| daemon | 可选 | False | 指定线程是否为守护线程。如果是,线程不会阻止程序退出。 |
import time
import threading
# 编写代码
def coding(num):
for i in range(num):
print("coding...")
time.sleep(0.2)
# 听音乐
def music(count):
for i in range(count):
print("music...")
time.sleep(0.2)
if __name__ == '__main__':
# 创建子线程
coding_thread = threading.Thread(target=coding, args=(3,))
music_thread = threading.Thread(target=music, kwargs={"count": 1})
# 启动子线程执行任务
coding_thread.start()
music_thread.start()
非守护(Non-Daemon)子线程:
守护(Daemon)子线程:
设置守护主线程有两种方式:
threading.Thread(target=work, daemon=True)(推荐)线程对象.setDaemon(True)(弃用)import time
import threading
# 工作函数
def work():
for i in range(10):
print("work...")
time.sleep(0.2)
if __name__ == '__main__':
# 创建子线程
# 方式1 参数方式设置守护主线程
work_thread = threading.Thread(target=work, daemon=True)
# work_thread = threading.Thread(target=work)
# 方式2(不推荐)
# work_thread.setDaemon(True)
# 启动线程
work_thread.start()
# 延时一秒
time.sleep(1)
print("主线程执行完毕")

# 通过current_thread方法获取线程对象
current_thread = threading.current_thread()
# 通过current_thread对象可以知道线程的相关信息,例如被创建的顺序
print(current_thread)

import threading
import time
# 全局变量
my_list = []
# 写入数据
def write_data():
for i in range(3):
print("add:", i)
my_list.append(i)
print("write:", my_list)
# 读取数据
def read_data():
print("read:", my_list)
if __name__ == '__main__':
# 创建子线程
write_thread = threading.Thread(target=write_data)
read_thread = threading.Thread(target=read_data)
# 启动线程
write_thread.start()
# 延时一秒
time.sleep(1)
read_thread.start()
定义两个函数,实现循环100万次,每循环一次给全局变量加1
创建两个子线程执行对应的两个函数,查看计算后的结果
import threading
# 全局变量
g_num = 0
# 对g_num进行加操作
def sum_num1():
for i in range(1000000):
global g_num
g_num += 1
print("g_num1:", g_num)
# 对g_num进行加操作
def sum_num2():
for i in range(1000000):
global g_num
g_num += 1
print("g_num2:", g_num)
if __name__ == '__main__':
# 创建子线程
sum1_thread = threading.Thread(target=sum_num1)
sum2_thread = threading.Thread(target=sum_num2)
# 启动线程
sum1_thread.start()
sum2_thread.start()

互斥锁的创建
mutex = threading.lock()
上锁
mutex.acquire()
释放锁
mutex.release()
import threading
# 全局变量
g_num = 0
# 对g_num进行加操作
def sum_num1():
global g_num
for i in range(1000000):
# 上锁
mutex.acquire()
g_num += 1
# 解锁
mutex.release()
# 对g_num进行加操作
def sum_num2():
global g_num
for i in range(1000000):
# 上锁
mutex.acquire()
g_num += 1
# 解锁
mutex.release()
if __name__ == '__main__':
# 创建锁
mutex = threading.Lock()
# 创建子线程
sum1_thread = threading.Thread(target=sum_num1)
sum2_thread = threading.Thread(target=sum_num2)
# 启动线程
sum1_thread.start()
sum2_thread.start()
# 等待线程执行结束
sum1_thread.join()
sum2_thread.join()
# 打印结果
print("g_num1:", g_num)
print("g_num2:", g_num)
一直等待对方释放锁的情景就是死锁
死锁的结果:会造成应用程序的停止响应,不能再处理其它任务。

产生死锁的原因:没有及时或者在正确的位置释放锁
死锁的注意点
举例
import threading
# 全局变量
g_num = 0
# 对g_num进行加操作
def sum_num1():
# 上锁
print("sun_num1...")
mutex.acquire()
for i in range(1000000):
global g_num
g_num += 1
print("g_num1:", g_num)
# 对g_num进行加操作
def sum_num2():
# 上锁
print("sun_num2...")
mutex.acquire()
for i in range(1000000):
global g_num
g_num += 1
print("g_num2:", g_num)
if __name__ == '__main__':
# 创建锁
mutex = threading.Lock()
# 创建子线程
sum1_thread = threading.Thread(target=sum_num1)
sum2_thread = threading.Thread(target=sum_num2)
# 启动线程
sum1_thread.start()
sum2_thread.start()
下面是一个简单的表格来对比进程和线程:
| 进程 | 线程 | |
|---|---|---|
| 关系 | 线程是依附在进程里面的 | 一个进程默认提供一条线程,进程可以创建多个线程 |
| 区别 | 进程之间不共享全局变量 | 线程之间共享全局变量,但要注意资源竞争问题 |
| 创建进程的资源开销大 | 创建线程的资源开销相对较小 | |
| 进程是操作系统资源分配的基本单位 | 线程是CPU调度的基本单位 | |
| 进程可以独立执行 | 线程不能独立执行,必须依托在进程中 | |
| 优缺点 | 优点:可以利用多核资源 | 优点:资源开销小 |
| 缺点:资源开销大 | 缺点:不能使用多核 |
总结: