进程与线程
关系区别:
线程依赖于进程,一个进程至少会有一个线程
特点区别:
- 进程间的数据是相互隔离的,线程间数据是可以共享的
- 线程同时操作共享数据, 可能引发安全问题,需要用到互斥锁
- 进程的资源开销比线程大
- 多进程程序比 单进程多线程程序要更加的稳定
优缺点:
1.进程:可以多核操作,资源开销较大
2.线程:不能多核,资源开销相对较小
总结:
1.线程依赖进程
2.进程数据隔离,线程数据共享
3.进程资源开销比线程大,更加稳定
4.无论是多线程还是多进程,目的都是:充分利用CPU资源,提高效率
进程格式:
import multiprocessing
if __name__ == '__main__':
# 创建进程p1
p1 = multiprocessing.Process(target=目标....)
# 参数有target进程链接对象 name进程名 args元组形式传参 kwargs字典形式传参
#启动进程
p1.start()
线程格式:
import threading
if __name__ == '__main__':
t1 = threading.Thread(target=....)
# 参数和进程一样有target进程链接对象 name进程名 args元组形式传参 kwargs字典形式传参
#启动进程
t1.start()
图解:
关系示例:
进程:
1.进程之间和main进程的关系
import multiprocessing
import time
'''
进程之间数据是相互隔离的
多进程之间针对于main进程的外部资源每个子进程都会拷贝一份进行执行
'''
# print('我是mian外')
def add_data(my_list):
for i in range(5):
my_list.append(i)
print(f'添加{i}成功!')
print(f'add_data函数:{my_list}')
def read_data(my_list):
time.sleep(1) # 保证add_data先执行
print(f'read_data函数:{my_list}')
if __name__ == '__main__':
my_list = []
p1 = multiprocessing.Process(target=add_data, args=(my_list,))
p1.start()
time.sleep(1)
print(my_list)
time.sleep(1)
p2 = multiprocessing.Process(target=read_data, args=(my_list,))
p2.start()
print('我是mian内')
2.main默认情况下主进程会等待子进程结束再结束
'''
默认情况下主进程会等待子进程结束再结束
可以设置子进程为守护进程
'''
import multiprocessing
import time
def my_method():
for i in range(10):
print(f'工作中...{i}')
time.sleep(0.3)
def fun2():
pass
if __name__ == '__main__':
# 设置进程为守护链接
p1 = multiprocessing.Process(target=my_method, daemon=True)
p1.start()
time.sleep(1)
print('主进程结束')
p1.kill()
线程:
1.带参数的多线程示例:
'''
线程是cpu调度资源的基本单位,进程是cpu分配资源的进本单位
进程 = 可执行程序,文件
线程 = 进程的执行路径,执行单元
无论是进程还是线程,都实现多任务的一种方式,目的都是充分利用CPU资源,提高效率
多线程带参数
target : 关联目标函数
name: 线程名或进程名
args: 以元组的形式传参数
kwargs : 以字典的形式传参数
'''
import threading, time
def coding(name, num):
for i in range(num):
# time.sleep(0.1)
print(f'{name}在写代码{i}')
def music(name, num):
for i in range(num):
# time.sleep(0.1)
print(f'{name}在听音乐{i}....')
if __name__ == '__main__':
t1 = threading.Thread(target=coding, args=('小明', 200))
t2 = threading.Thread(target=music, kwargs={'name': '小红', 'num': 200})
t1.start()
t2.start()
2.多线程操控资源的安全性问题,可以通过加锁来避免
无锁版:
'''
多线程的执行具有随机性,就是在强cpu的过程,谁抢到,谁执行
默认情况下主线程会等待子线程执行结束在结束
线程之间会共享当前进程的资源
多线程环境 并发 操作共享资源, 有可能引发安全问题,需要通过 线程同步(加锁) 的思想来解决
CPU的资源分配,调度:
1.均分时间片,即:每个进程(线程)占用CPU的时间都是相等的
2.抢占式调度,谁抢到,谁执行,Python用的这种
多线程并发操作共享全局变量,引发安全问题
'''
import threading
import time
num = 0
def add_num():
global num
for i in range(1000000):
num += 1
print(f'1ok:{num}')
def add_num2():
global num
for i in range(1000000):
num += 1
print(f'2ok:{num}')
if __name__ == '__main__':
t1 = threading.Thread(target=add_num)
t2 = threading.Thread(target=add_num2)
t1.start()
t2.start()
print(num)
运行结果可以发现同时操作数据后,结果比我们预期的2000000要少
加锁版:
import threading
import time
num = 0
# 定义互斥锁
mutex = threading.Lock()
def add_num():
#开启锁
mutex.acquire()
global num
for i in range(1000000):
num += 1
print(f'1ok:{num}')
#关闭锁
mutex.release()
def add_num2():
#开启锁
mutex.acquire() # 保证t1和t2操作num是互斥的
global num
for i in range(1000000):
num += 1
print(f'2ok:{num}')
#关闭锁
mutex.release()
if __name__ == '__main__':
t1 = threading.Thread(target=add_num)
t2 = threading.Thread(target=add_num2)
t1.start()
t2.start()
mutex.acquire()
print(num)
mutex.release()
这里运行就会输出我们预期的结果.