XX学Python·进程与线程
多任务编程-进程
-
多任务执行方式
-
并发:在一段时间内交替去执行任务
-
并行:多核cpu每个cpu执行一个任务。注:任务>cpu时,每个cpu并发执行多个任务
-
-
进程:计算机中的程序关于某数据集合上的一次运行活动,是操作系统资源(内存)分配的基本单位。一个程序运行后至少有一个进程,一个进程至少有一个线程。
-
一个进程就开辟一块内存空间,多线程是利用一个内存空间
-
多进程的基本使用:
# def login():
# print('登录')
#
#
# if __name__ == '__main__':
# login()
# login()
# # 上面相当于在一个进程里面执行了多次方法。同一内存块里。
# 使用多进程的形式完成多次调用。相当于把程序复制后在不同的内存空间单独执行。
import multiprocessing # 导入多进程模块
def login():
print('登录')
# p1 = multiprocessing.Process(target=login())
# p1.start()
# 上面没放入if __name里运行报错,系统认为原有方法要执行一次,相当于重复运行。
if __name__ == '__main__': # 多进程要放入if __name__里
# Process括号里参数:
# group=None 指定分组,推荐使用默认None,
# target=None 指定要调用的函数名,常用
# name=None 指定进程名称,
# args=()元组传参注意一个元素('xx',), kwargs={}给函数传递参数
# daemon=None 指定守护进程
# Process是一个类,注意不能用小写process
# Process中target指定的是子进程要执行的任务,所以切记任务后面不要添加括号
p1 = multiprocessing.Process(target=login) # 创建了一个进程
p2 = multiprocessing.Process(target=login) # 相当于创建了一个实例对象
p1.start() # 运行进程指定对应函数业务逻辑
p2.start() # 使用start运行
-
进程编号:子进程是由主进程创建出来的。
-
获取当前进程编号:os.getpid()
-
获取当前父进程编号:os.getppid()
-
import multiprocessing
import os
def login(name, password):
print('名字:', name)
print('密码:', password)
print('登录')
# 获取当前进程名称
print('进程名称:', multiprocessing.current_process().name)
# 获取当前进程编号,这里获取就是子进程
print('子进程:', os.getpid())
# 获取主进程编号,pid前面加了一个p,父进程
print('子进程的父进程编号:', os.getppid())
if __name__ == '__main__':
# group=None 指定分组,推荐使用默认None
# target=None 指定要调用的函数名
# name=None 指定进程名称
# args=(), kwargs={}给函数传递参数,
# daemon=None 指定守护进程
p1 = multiprocessing.Process(target=login, args=('Python', 123456), name='p1')
p2 = multiprocessing.Process(target=login, kwargs={'name': 'xx', 'password': 123456}, name='p2')
p3 = multiprocessing.Process(target=login, kwargs={'name': 'lsl', 'password': 123456}, name='p3')
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
# 如果需要进程按照循序执行,需要用进程等待join方法,但一般不用。
# 不用join,顺序就不一定,是cpu根据他的调用算法随机执行
# 获取当前进程编号,使用os模块。这里获取的主进程编号。
print('主进程:', os.getpid())
-
进程注意点
-
进程间不共享全局变量
-
正常情况下主进程会等待子进程结束后在退出主进程
-
import multiprocessing
# 不共享全局变量
data_list = []
def write_data():
# 往全局列表中写入数据
for i in range(0, 50):
print(i)
data_list.append(i)
print('write_data方法写入的数据为:', data_list)
def read_data():
print('read_data方法读取的数据为:', data_list)
if __name__ == '__main__':
# 创建多进程分别调用两个读写方法,验证全局变量是否共享数据
p1 = multiprocessing.Process(target=write_data, daemon=True)
p2 = multiprocessing.Process(target=read_data)
p1.start()
p2.start()
# 正常情况下主进程会等待子进程结束后在退出主进程
# 需求主进程结束后就结束子进程,不再进行等待
# 两种形式实现 第一种设置守护进程参数daemon=True或 子进程对象.daemon=True
# 第二种 主动关闭子进程
p2.terminate()
print('主进程读取的数据:', data_list)
多任务编程-线程
-
线程:是操作系统运算调度的最小单位。被包含在进程之中,是进程实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
-
线程的基本使用
# 导入线程模块
import threading
def func(data):
print('线程使用')
print(f'参数数据:{data}')
# 获取当前执行线程的名称
print('线程名称:', threading.current_thread().name)
if __name__ == '__main__':
# 创建线程
# group = None, 使用默认
# target = None, 指定函数方法
# name = None, 指定线程名称
# args = (), kwargs = None, 传递参数
# daemon = None 设置守护线程
t1 = threading.Thread(target=func, args=('python',), name='t1')
t2 = threading.Thread(target=func, kwargs={'data': 'itcast'}, name='t2')
# 启动运行线程
t1.start()
t2.start()
-
线程注意点
-
线程执行是无序的,根据cpu随机调度
-
主线程会等待子线程结束后在结束:指定守护线程或线程对象.setDaemon(True),当主线程结束后自动结束子线程
-
线程间共享全局变量。但要注意无序执行导致的数据错乱,使用join等待
-
import threading
data = 0
def func1():
global data
for i in range(0, 1000000):
data += 1
print(f'函数1的累加结果:{data}')
def func2():
global data
for i in range(0, 1000000):
data += 1
print(f'函数2的累加结果:{data}')
if __name__ == '__main__':
# 创建两个线程进程累加
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
# 通过join的形式让函数顺序执行
t1.start()
t1.join()
t2.start()
t2.join()
print(f'主线程的结果展示:{data}')