|
一.并发和并行
- 多任务:一定时间段内,充分利用cpu资源,同时去执行多个任务
- 并发: 快速交替的 去执行多任务
- 并行: 真正同时的 去执行多任务 ,就是同时进行
二.多进程
1.多进程入门
知识点:
- 进程含义: 运行中的程序
- 进程特点: cpu资源分配的 最小单位
- 多进程模块: multiprocessing
- 进程类: Process
使用步骤:
- 导包 : import multiprocessing
- 创建对象 : 子进程对象 = multiprocessing.Process(target=任务名)
- 开启进程 : 子进程对象.start()
示例:- import multiprocessing
- import time
- # 任务1
- def dance():
- for i in range(5):
- time.sleep(0.1)
- print('跳舞',i)
- # 任务2
- def sing():
- for i in range(5):
- time.sleep(0.3)
- print('唱歌',i)
- # 多进程放到main内
- if __name__ == '__main__':
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=dance)
- p2 = multiprocessing.Process(target=sing)
- # 2.开启进程
- p1.start()
- p2.start()
复制代码 2.os模块获取进程编号
知识点:- 获取当前进程id: os.getpid() pid: processing id
- 获取父进程id: os.getppid() ppid: parent processing id
复制代码 示例:- import multiprocessing
- import os
- import time
- # 任务1
- def dance():
- print('dance子进程:', os.getpid(), os.getppid())
- for i in range(5):
- time.sleep(0.1)
- print('跳舞',i)
- # 任务2
- def sing():
- print('sing子进程:', os.getpid(),os.getppid())
- for i in range(5):
- time.sleep(0.3)
- print('唱歌',i)
- # 多进程放到main内
- if __name__ == '__main__':
- print('main主进程:',os.getpid())
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=dance)
- p2 = multiprocessing.Process(target=sing)
- # 2.开启进程
- p1.start()
- p2.start()
复制代码 3.Process()类的传参,2种方式
知识点:
- args: 以元组方式传参 注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
- kwargs: 以字典方式传参 注意:需要{k:v}形式传参,k必须和任务的形参名一致
示例:- import multiprocessing
- import os
- import time
- # 任务1
- def dance(num):
- print('dance子进程:', os.getpid(), os.getppid())
- for i in range(num):
- time.sleep(0.1)
- print('跳舞',i)
- # 任务2
- def sing(num):
- print('sing子进程:', os.getpid(), os.getppid())
- for i in range(num):
- time.sleep(0.3)
- print('唱歌',i)
- # 多进程放到main内
- if __name__ == '__main__':
- print('main主进程:', os.getpid())
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=dance,args=(5,))
- p2 = multiprocessing.Process(target=sing,kwargs={'num':5})
- # 2.开启进程
- p1.start()
- p2.start()
复制代码 4.获取当前进程信息
知识点:
- 获取当前进程对象: multiprocessing.current_process()
- 获取当前进程name: multiprocessing.current_process().name
- 获取当前进程pid: multiprocessing.current_process().pid
示例:- import multiprocessing
- # 任务1
- def dance():
- print('dance子进程对象:', multiprocessing.current_process())
- print('dance子进程name:', multiprocessing.current_process().name)
- print('dance子进程id:', multiprocessing.current_process().pid)
- # 任务2
- def sing():
- print('sing子进程对象:', multiprocessing.current_process())
- print('sing子进程name:', multiprocessing.current_process().name)
- print('sing子进程id:', multiprocessing.current_process().pid)
- # 多进程放到main内
- if __name__ == '__main__':
- print('main主进程对象:', multiprocessing.current_process())
- print('main主进程name:', multiprocessing.current_process().name)
- print('main主进程id:', multiprocessing.current_process().pid)
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=dance,name='danceProcess')
- p2 = multiprocessing.Process(target=sing,name='singProcess')
- # 2.开启进程
- p1.start()
- p2.start()
复制代码 5.注意事项
1. 多进程间不能共享全局变量:- import multiprocessing
- mylist = []
- # 写
- def write():
- global mylist
- mylist = [1,2,3,4,5]
- print('write:',mylist) # [1, 2, 3, 4, 5]
- # 读
- def read():
- global mylist
- print('read:',mylist) # [] 说明多个进程间不共享全局变量
- # 多进程需要放到main内
- if __name__ == '__main__':
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=write)
- p2 = multiprocessing.Process(target=read)
- # 2.开启进程
- p1.start()
- p2.start()
复制代码 2. 主进程默认等待子进程结束再结束:- import multiprocessing
- import time
- # 任务
- def task():
- for i in range(10):
- print('任务进行中...')
- time.sleep(0.2)
- # 多任务
- if __name__ == '__main__':
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=task)
- # 2.开启进程
- p1.start()
- # 3.主进程等待0.5秒
- time.sleep(0.5)
- print('主进程中最后一行代码....')
复制代码 2. 主进程默认等待子进程结束再结束:- import multiprocessing
- import time
- # 任务
- def task():
- for i in range(10):
- print('任务进行中...')
- time.sleep(0.2)
- # 多任务
- if __name__ == '__main__':
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=task)
- # 2.开启进程
- p1.start()
- # 3.主进程等待0.5秒
- time.sleep(0.5)
- print('主进程中最后一行代码....')
复制代码 3. 多进程执行是无序的:- import multiprocessing
- import time
- # 任务
- def show():
- time.sleep(2)
- print(multiprocessing.current_process().name)
- # 学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
- # 多任务
- if __name__ == '__main__':
- for _ in range(5):
- # 创建进程对象
- p = multiprocessing.Process(target=show)
- # 开启进程
- p.start()
复制代码 6.设置子进程跟着主进程一起结束#
知识点:- 方式1 设置子进程守护主进程: 子进程对象.daemon = True 注意: 需要在开启进程之前设置
- : daemon/ˈdiːmən/守护进程
- 方式2 手动销毁子进程 : 子进程对象.terminate() terminate:结束,终止
复制代码 1. 守护主进程:- import multiprocessing
- import time
- # 任务
- def task():
- for i in range(10):
- print('任务进行中...')
- time.sleep(0.2)
- # 多任务
- if __name__ == '__main__':
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=task)
- # 方式1: 开启子进程之前设置守护主进程
- p1.daemon = True
- # 2.开启进程
- p1.start()
- # 3.主进程等待0.5秒
- time.sleep(0.5)
- print('主进程中最后一行代码....')
复制代码 2. 手动销毁子进程:- import multiprocessing
- import time
- # 任务
- def task():
- for i in range(10):
- print('任务进行中...')
- time.sleep(0.2)
- # 多任务
- if __name__ == '__main__':
- # 1.创建进程对象
- p1 = multiprocessing.Process(target=task)
- # 2.开启进程
- p1.start()
- # 3.主进程等待0.5秒
- time.sleep(0.5)
- print('主进程中最后一行代码....') # 方式2: 手动销毁子进程 p1.terminate()
复制代码 三.多线程
1.多线程入门
知识点:
- 线程含义: 进程中 执行代码的 一个分支 (一个进程至少有一个线程)
- 线程作用: 线程是 cpu调度的 最小单位
- 多线程模块: threading
- 线程类: Thread
使用步骤:
- 导包 : import threading
- 创建对象 : 子线程对象 = threading.Thread(target=任务名)
- 开启进程 : 子线程对象.start()
示例:- import threading
- # 任务1
- def dance():
- for i in range(5):
- print('跳舞',i)
- # 任务2
- def sing():
- for i in range(5):
- print('唱歌',i)
- # 多任务
- if __name__ == '__main__':
- # 1.创建子线程对象
- t1 = threading.Thread(target=dance)
- t2 = threading.Thread(target=sing)
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 2.多线程的传参
知识点:
args: 以元组方式传参 注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
kwargs: 以字典方式传参 注意:需要{k:v}形式传参,k必须和任务的形参名一致
与多进程一模一样
示例:- import threading
- """
- args: 以元组方式传参 注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
- kwargs: 以字典方式传参 注意:需要{k:v}形式传参,k必须和任务的形参名一致
- """
- # 任务1
- def dance(num):
- for i in range(num):
- print('跳舞', i)
- # 任务2
- def sing(num):
- for i in range(num):
- print('唱歌', i)
- # 多任务
- if __name__ == '__main__':
- # 1.创建子线程对象
- t1 = threading.Thread(target=dance,args=(5,))
- t2 = threading.Thread(target=sing,kwargs={'num':5})
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 3.多线程注意事项
- import os
- import threading
- """
- args: 以元组方式传参 注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
- kwargs: 以字典方式传参 注意:需要{k:v}形式传参,k必须和任务的形参名一致
- """
- # 任务1
- def dance(num):
- print(f'dance子线程中当前进程pid:{os.getpid()}')
- for i in range(num):
- print('跳舞', i)
- # 任务2
- def sing(num):
- print(f'sing子线程中当前进程pid:{os.getpid()}')
- for i in range(num):
- print('唱歌', i)
- # 多任务
- if __name__ == '__main__':
- print(f'main主线程中当前进程pid:{os.getpid()}')
- # 1.创建子线程对象
- t1 = threading.Thread(target=dance,args=(5,))
- t2 = threading.Thread(target=sing,kwargs={'num':5})
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 2. 多线程是可以共享全局变量- import threading
- mylist = []
- # 写
- def write():
- global mylist
- mylist = [1,2,3,4,5]
- print('write:',mylist) # [1, 2, 3, 4, 5]
- # 读
- def read():
- global mylist
- print('read:',mylist) # [1, 2, 3, 4, 5] 访问到了write线程修改后的内容说明多线程共享全局变量
- if __name__ == '__main__':
- # 1.创建线程对象
- t1 = threading.Thread(target=write)
- t2 = threading.Thread(target=read)
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 3. 主线程默认等待子线程结束再结束- import threading
- import time
- # 任务
- def task():
- for i in range(10):
- print('任务进行中...')
- time.sleep(0.2)
- # 多任务
- if __name__ == '__main__':
- # 1.创建线程对象
- t = threading.Thread(target=task)
- # 2.开启线程
- t.start()
- # 3.为了效果明显点,主线程等待0.5秒
- time.sleep(0.5)
- print('主线程中最后一行代码....')
复制代码 4. 多线程是无序的- import threading
- import time
- # 任务
- def show():
- time.sleep(1)
- print(threading.current_thread().name)
- # 多任务
- if __name__ == '__main__':
- for _ in range(5):
- # 创建线程对象
- p = threading.Thread(target=show)
- # 开启线程
- p.start()
复制代码 4.设置守护主线程
知识点:- 方式1: daemon属性 t.daemon = True daemon/ˈdiːmən/守护进程
-
- 方式2: setDaemon()方法 t.setDaemon(True)
复制代码 一个是属性,一个是方法,用哪个都可以
示例:- import threading
- import time
- # 任务
- def task():
- for i in range(10):
- print('任务进行中...')
- time.sleep(0.2)
- # 多任务
- if __name__ == '__main__':
- # 1.创建线程对象
- t = threading.Thread(target=task)
-
- # 方式1: daemon属性
- # t.daemon = True
- # 方式2: setDaemon()方法
- t.setDaemon(True)
- # 2.开启线程
- t.start()
- # 3.为了效果明显点,主线程等待0.5秒
- time.sleep(0.5)
- print('主线程中最后一行代码....')
复制代码 5.获取当前线程信息
知识点:
- 获取当前线程对象:threading.current_thread()
- 获取当前线程name:threading.current_thread().name
- 获取当前线程id:threading.current_thread().native_id
示例:- import threading
- def dance():
- print(f'dance当前线程对象:{threading.current_thread()}')
- print(f'dance当前线程name:{threading.current_thread().name}')
- print(f'dance当前线程id:{threading.current_thread().native_id}')
- def sing():
- print(f'sing当前线程对象:{threading.current_thread()}')
- print(f'sing当前线程name:{threading.current_thread().name}')
- print(f'sing当前线程id:{threading.current_thread().native_id}')
- if __name__ == '__main__':
- print(f'main当前线程对象:{threading.current_thread()}')
- print(f'main当前线程name:{threading.current_thread().name}')
- print(f'main当前线程id:{threading.current_thread().native_id}')
- # 1.创建线程对象
- t1 = threading.Thread(target=dance,name='DanceThread')
- t2 = threading.Thread(target=sing,name='SingThread')
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 6.线程安全问题
1. 出现的线程安全问题:- import threading
- sum = 0
- def sum1():
- global sum
- for i in range(1000000):
- sum += 1
- print(sum) # 1114834
- def sum2():
- global sum
- for i in range(1000000):
- sum += 1
- print(sum) # 1339347
- # 单任务不会出现问题 正常结果 1000000 2000000
- # 多任务出现了问题
- if __name__ == '__main__':
- # 1.创建线程对象
- t1 = threading.Thread(target=sum1)
- t2 = threading.Thread(target=sum2)
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 2. 锁机制解决线程安全问题:- import threading
- sum = 0
- def sum1(lock):
- lock.acquire() # 加锁
- global sum
- for i in range(1000000):
- sum += 1
- print(sum) # 1000000
- lock.release() # 释放锁
- def sum2(lock):
- lock.acquire() # 加锁
- global sum
- for i in range(1000000):
- sum += 1
- print(sum) # 2000000
- lock.release() # 释放锁
- # 单任务不会出现问题 正常结果 1000000 2000000
- # 多任务出现了问题 ,利用锁机制解决问题
- if __name__ == '__main__':
- # 创建一个锁,保证两个任务用的是同一个锁
- lock= threading.Lock()
- # 1.创建线程对象
- t1 = threading.Thread(target=sum1,args=(lock,))
- t2 = threading.Thread(target=sum2,args=(lock,))
- # 2.开启线程
- t1.start()
- t2.start()
复制代码 3. join解决线程安全问题:- import threading
- sum = 0
- def sum1():
- global sum
- for i in range(1000000):
- sum += 1
- print(sum) # 1000000
- def sum2():
- global sum
- for i in range(1000000):
- sum += 1
- print(sum) # 2000000
- # 学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
- # 单任务不会出现问题 正常结果 1000000 2000000
- # 多任务出现了问题 ,利用join解决问题
- if __name__ == '__main__':
- # 1.创建线程对象
- t1 = threading.Thread(target=sum1)
- t2 = threading.Thread(target=sum2)
- # 2.开启线程
- t1.start()
- t1.join() # t1线程告诉其他线程等我执行完,你们其他线程再执行
- t2.start()
复制代码 四.进程和线程对比
关系
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条线程,进程可以创建多个线程
区别
- 进程之间不共享全局变量
- 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法是互斥锁或者线程同步
- 创建进程的资源开销要比创建线程的资源开销要大
- 进程是操作系统 资源分配 的基本单位,线程是 CPU调度 的基本单位
- 线程不能够独立执行,必须依存在进程中
- 多进程开发比单进程多线程开发稳定性要强
优缺点
进程优缺点:
优点:可以用多核
缺点:资源开销大
线程优缺点:
优点:资源开销小
缺点:不能使用多核
来源:https://www.cnblogs.com/python1111/p/17128261.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|