1.使用多任务能充分利用CPU资源,提高程序的执行效率,让程序具备处理多任务的能力。
2.多任务执行方式有两种:
并发:在一段时间内交替执行多个任务。
并行:在一段时间内真正的同时一起执行多个任务。
1.进程(Process)是资源分配的最小单位。
2.多进程是Python程序中实现多任务的一种方式,使用多进程可以大大提高程序的执行效率。
1.导入进程包。
2.创建子进程并指定执行的任务。
3.启动进程执行任务。
- # 导入进程模块
- 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()
- # music()
- # 通过进程类创建进程对象
- coding_process = multiprocessing.Process(target=coding)
- music_process = multiprocessing.Process(target=music)
- # 启动进程
- coding_process.start()
- music_process.start()
进程执行带有参数的任务有两种方式:
1.元组方式传参:元组方式传参一定要和参数的顺序保持一致。
2.字典方式传参:字典方式传参字典中的key一定要和参数名保持一致。
- # 导入进程模块
- 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()
- # music()
- # 通过进程类创建进程对象
- coding_process = multiprocessing.Process(target=coding,args=(3,"zs"))
- music_process = multiprocessing.Process(target=music,kwargs={"count":2})
- # 启动进程
- coding_process.start()
- music_process.start()
1.获取当前进程编号
os.getpid()
2.获取当前父进程编号
os.getppid()
- # 导入进程模块
- import multiprocessing
- import os
- import time
-
- # 敲代码
- def coding():
- # 获取coding_process的编号
- print("coding_process>>>%d" % os.getpid())
- # 获取coding_process的父进程的编号
- print("coding_process的父进程>>>%d" % os.getppid())
- for i in range(3):
- print("coding...")
- time.sleep(0.2)
-
- # 听音乐
- def music():
- # 获取music_process的编号
- print("music_process>>>%d" % os.getpid())
- # 获取music_process的父进程的编号
- print("music_process的父进程>>>%d" % os.getppid())
- for i in range(3):
- print("music...")
- time.sleep(0.2)
-
- if __name__ == '__main__':
- # 获取主进程的编号
- print("主进程>>>%d" % os.getpid())
- # 通过进程类创建进程对象
- coding_process = multiprocessing.Process(target=coding)
- music_process = multiprocessing.Process(target=music)
- # 启动进程
- coding_process.start()
- music_process.start()
两个子进程的父进程的编号与主进程的编号相同,证明两个子进程是由该父进程创建并启动的。
- 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()
写入数据进程和读取数据进程不共享my_list这个全局变量。
默认情况下,为了保证子进程能够正常的运行,主进程会等待所有的子进程执行完后再结束。
如果想要让主进程结束后子进程就销毁,可以采取以下两种方式:
- 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.daemon = True
-
- # 启动子进程
- work_process.start()
-
- # 延时1秒
- time.sleep(1)
-
- # 方式二:手动销毁子进程
- work_process.terminate()
-
- print("主进程执行完毕")
1.多线程是Python程序中实现多任务的一种方式。
2.线程是程序执行的最小单位。
3.同属一个进程的多个线程共享进程所拥有的全部资源。
1.导入线程模块
2.创建子线程
3.启动线程执行任务
- import time
- import threading
-
- # 敲代码
- 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_thread = threading.Thread(target=coding)
- music_thread = threading.Thread(target=music)
- # 启动线程执行任务
- coding_thread.start()
- music_thread.start()
线程执行带有参数的任务有两种方式:
1.元组方式传参:元组方式传参一定要和参数的顺序保持一致。
2.字典方式传参:字典方式传参字典中的key一定要和参数名保持一致。
- 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" : 2})
- # 启动线程执行任务
- coding_thread.start()
- music_thread.start()
默认情况下,为了保证子线程够正常的运行,主线程会等待所有的子线程执行完后再结束。
如果想要让主线程结束后子线程就销毁,可以采取以下两种方式:
- import time
- import threading
-
- # 工作函数
- def work():
- for i in range(10):
- print("work...")
- time.sleep(0.2)
-
- if __name__ == '__main__':
- # 创建线程
- # 方式一:参数方式设置守护主线程
- # work_thread = threading.Thread(target=work,daemon=True)
- work_thread = threading.Thread(target=work)
-
- # 方式二:方法方式设置守护主线程
- work_thread.setDaemon(True)
-
- # 启动线程执行任务
- work_thread.start()
-
- # 延时1秒
- time.sleep(1)
- print("主线程执行完毕")
线程之间执行是无序的,是由CPU调度决定某个线程先执行的。
- import threading
- import time
-
- # 获取线程信息函数
- def get_info():
- time.sleep(0.5)
- # 获取线程信息
- current_thread = threading.current_thread()
- print(current_thread)
-
- if __name__ == '__main__':
- for i in range(10):
- # 创建子线程
- sub_thread = threading.Thread(target=get_info)
- # 启动线程执行任务
- sub_thread.start()
- import threading
- 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_thread = threading.Thread(target=write_data)
- # 创建读取数据线程
- read_thread = threading.Thread(target=read_data)
-
- # 启动线程,执行任务
- write_thread.start()
- time.sleep(1)
- read_thread.start()
线程间共享my_list这个共享变量。
多线程同时操作全局变量可能会导致数据出现错误,可以使用线程同步方式来解决这个问题。
线程同步方式:
- 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()
1.互斥锁的使用
threading.Lock()
2.上锁
mutex.acquire()
3.解锁
mutex.release()
- import threading
-
- # 全局变量
- g_num = 0
-
- # 对g_num进行加操作
- def sum_num1():
- # 上锁
- mutex.acquire()
-
- for i in range(1000000):
- # 声明全局变量
- global g_num
- g_num += 1
-
- # 解锁
- mutex.release()
-
- print("g_num1:",g_num)
-
-
-
- # 对g_num进行加操作
- def sum_num2():
- # 上锁
- mutex.acquire()
- for i in range(1000000):
- # 声明全局变量
- global g_num
- g_num += 1
-
- # 解锁
- mutex.release()
-
- 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()
死锁:一直等待对方释放锁的情景就是死锁。
死锁的结果:会造成应用程序停止响应,不能再处理其它任务了。
死锁的注意点:
- import threading
-
- # 全局变量
- g_num = 0
-
- # 对g_num进行加操作
- def sum_num1():
- print("sum_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("sum_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()
线程sum1_thread占用锁资源,而线程sum2_thread请求锁资源,导致死锁,线程无法继续运行下去。
线程是依附在进程里面的,没有进程就没有线程。
一个进程默认提供一条线程,当然进程可以创建多个线程。
进程之间不共享全局变量,而线程之间共享全局变量(但是要注意资源竞争的问题)。
创建进程的资源开销大于线程。
进程是OS资源分配的基本单位,线程是CPU调度的基本单位。
线程不能独立执行,必须依存在进程中。
1.进程优缺点:
优点:可以用多核(多个进程并行执行)。
缺点:资源开销大。
2.线程优缺点:
优点:资源开销小。
缺点:只能使用单核(多个线程并发执行)。