翼度科技»论坛 编程开发 python 查看内容

Python多任务教程

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
一.并发和并行


  • 多任务:一定时间段内,充分利用cpu资源,同时去执行多个任务
  • 并发: 快速交替的 去执行多任务
  • 并行: 真正同时的 去执行多任务 ,就是同时进行
二.多进程

1.多进程入门

知识点:

  • 进程含义: 运行中的程序
  • 进程特点: cpu资源分配的 最小单位
  • 多进程模块: multiprocessing
  • 进程类:         Process
使用步骤:

  • 导包 : import multiprocessing
  • 创建对象 : 子进程对象 = multiprocessing.Process(target=任务名)
  • 开启进程 : 子进程对象.start()
示例:
  1. import multiprocessing
  2. import time
  3. # 任务1
  4. def dance():
  5.     for i in range(5):
  6.         time.sleep(0.1)
  7.         print('跳舞',i)
  8. # 任务2
  9. def sing():
  10.     for i in range(5):
  11.         time.sleep(0.3)
  12.         print('唱歌',i)
  13. # 多进程放到main内
  14. if __name__ == '__main__':
  15.     # 1.创建进程对象
  16.     p1 = multiprocessing.Process(target=dance)
  17.     p2 = multiprocessing.Process(target=sing)
  18.     # 2.开启进程
  19.     p1.start()
  20.     p2.start()
复制代码
2.os模块获取进程编号

知识点:
  1. 获取当前进程id: os.getpid()   pid: processing id
  2. 获取父进程id: os.getppid()   ppid: parent processing id
复制代码
示例:
  1. import multiprocessing
  2. import os
  3. import time
  4. # 任务1
  5. def dance():
  6.     print('dance子进程:', os.getpid(), os.getppid())
  7.     for i in range(5):
  8.         time.sleep(0.1)
  9.         print('跳舞',i)
  10. # 任务2
  11. def sing():
  12.     print('sing子进程:', os.getpid(),os.getppid())
  13.     for i in range(5):
  14.         time.sleep(0.3)
  15.         print('唱歌',i)
  16. # 多进程放到main内
  17. if __name__ == '__main__':
  18.     print('main主进程:',os.getpid())
  19.     # 1.创建进程对象
  20.     p1 = multiprocessing.Process(target=dance)
  21.     p2 = multiprocessing.Process(target=sing)
  22.     # 2.开启进程
  23.     p1.start()
  24.     p2.start()
复制代码
3.Process()类的传参,2种方式

知识点:

  • args: 以元组方式传参   注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
  • kwargs: 以字典方式传参  注意:需要{k:v}形式传参,k必须和任务的形参名一致
示例:
  1. import multiprocessing
  2. import os
  3. import time
  4. # 任务1
  5. def dance(num):
  6.     print('dance子进程:', os.getpid(), os.getppid())
  7.     for i in range(num):
  8.         time.sleep(0.1)
  9.         print('跳舞',i)
  10. # 任务2
  11. def sing(num):
  12.     print('sing子进程:', os.getpid(), os.getppid())
  13.     for i in range(num):
  14.         time.sleep(0.3)
  15.         print('唱歌',i)
  16. # 多进程放到main内
  17. if __name__ == '__main__':
  18.     print('main主进程:', os.getpid())
  19.     # 1.创建进程对象
  20.     p1 = multiprocessing.Process(target=dance,args=(5,))
  21.     p2 = multiprocessing.Process(target=sing,kwargs={'num':5})
  22.     # 2.开启进程
  23.     p1.start()
  24.     p2.start()
复制代码
4.获取当前进程信息

知识点:

  • 获取当前进程对象: multiprocessing.current_process()
  • 获取当前进程name: multiprocessing.current_process().name
  • 获取当前进程pid: multiprocessing.current_process().pid
示例:
  1. import multiprocessing
  2. # 任务1
  3. def dance():
  4.     print('dance子进程对象:', multiprocessing.current_process())
  5.     print('dance子进程name:', multiprocessing.current_process().name)
  6.     print('dance子进程id:', multiprocessing.current_process().pid)
  7. # 任务2
  8. def sing():
  9.     print('sing子进程对象:', multiprocessing.current_process())
  10.     print('sing子进程name:', multiprocessing.current_process().name)
  11.     print('sing子进程id:', multiprocessing.current_process().pid)
  12. # 多进程放到main内
  13. if __name__ == '__main__':
  14.     print('main主进程对象:', multiprocessing.current_process())
  15.     print('main主进程name:', multiprocessing.current_process().name)
  16.     print('main主进程id:', multiprocessing.current_process().pid)
  17.     # 1.创建进程对象
  18.     p1 = multiprocessing.Process(target=dance,name='danceProcess')
  19.     p2 = multiprocessing.Process(target=sing,name='singProcess')
  20.     # 2.开启进程
  21.     p1.start()
  22.     p2.start()
复制代码
5.注意事项

1. 多进程间不能共享全局变量:
  1. import multiprocessing
  2. mylist = []
  3. # 写
  4. def write():
  5.     global mylist
  6.     mylist = [1,2,3,4,5]
  7.     print('write:',mylist) # [1, 2, 3, 4, 5]
  8. # 读
  9. def read():
  10.     global mylist
  11.     print('read:',mylist)  # []  说明多个进程间不共享全局变量
  12. # 多进程需要放到main内
  13. if __name__ == '__main__':
  14.     # 1.创建进程对象
  15.     p1 = multiprocessing.Process(target=write)
  16.     p2 = multiprocessing.Process(target=read)
  17.     # 2.开启进程
  18.     p1.start()
  19.     p2.start()
复制代码
2. 主进程默认等待子进程结束再结束:
  1. import multiprocessing
  2. import time
  3. # 任务
  4. def task():
  5.     for i in range(10):
  6.         print('任务进行中...')
  7.         time.sleep(0.2)
  8. # 多任务
  9. if __name__ == '__main__':
  10.     # 1.创建进程对象
  11.     p1 = multiprocessing.Process(target=task)
  12.     # 2.开启进程
  13.     p1.start()
  14.     # 3.主进程等待0.5秒
  15.     time.sleep(0.5)
  16.     print('主进程中最后一行代码....')
复制代码
2. 主进程默认等待子进程结束再结束:
  1. import multiprocessing
  2. import time
  3. # 任务
  4. def task():
  5.     for i in range(10):
  6.         print('任务进行中...')
  7.         time.sleep(0.2)
  8. # 多任务
  9. if __name__ == '__main__':
  10.     # 1.创建进程对象
  11.     p1 = multiprocessing.Process(target=task)
  12.     # 2.开启进程
  13.     p1.start()
  14.     # 3.主进程等待0.5秒
  15.     time.sleep(0.5)
  16.     print('主进程中最后一行代码....')
复制代码
3. 多进程执行是无序的:
  1. import multiprocessing
  2. import time
  3. # 任务
  4. def show():
  5.     time.sleep(2)
  6.     print(multiprocessing.current_process().name)
  7. # 学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
  8. # 多任务
  9. if __name__ == '__main__':
  10.     for _ in range(5):
  11.         # 创建进程对象
  12.         p = multiprocessing.Process(target=show)
  13.         # 开启进程
  14.         p.start()
复制代码
6.设置子进程跟着主进程一起结束#

知识点:
  1. 方式1 设置子进程守护主进程:  子进程对象.daemon = True   注意: 需要在开启进程之前设置   
  2.        :                          daemon/ˈdiːmən/守护进程
  3. 方式2 手动销毁子进程     :  子进程对象.terminate()    terminate:结束,终止
复制代码
1. 守护主进程:
  1. import multiprocessing
  2. import time
  3. # 任务
  4. def task():
  5.     for i in range(10):
  6.         print('任务进行中...')
  7.         time.sleep(0.2)
  8. # 多任务
  9. if __name__ == '__main__':
  10.     # 1.创建进程对象
  11.     p1 = multiprocessing.Process(target=task)
  12.     # 方式1: 开启子进程之前设置守护主进程
  13.     p1.daemon = True
  14.     # 2.开启进程
  15.     p1.start()
  16.     # 3.主进程等待0.5秒
  17.     time.sleep(0.5)
  18.     print('主进程中最后一行代码....')
复制代码
2. 手动销毁子进程:
  1. import multiprocessing
  2. import time
  3. # 任务
  4. def task():
  5.     for i in range(10):
  6.         print('任务进行中...')
  7.         time.sleep(0.2)
  8. # 多任务
  9. if __name__ == '__main__':
  10.     # 1.创建进程对象
  11.     p1 = multiprocessing.Process(target=task)
  12.     # 2.开启进程
  13.     p1.start()
  14.     # 3.主进程等待0.5秒
  15.     time.sleep(0.5)
  16.     print('主进程中最后一行代码....')        # 方式2: 手动销毁子进程    p1.terminate()
复制代码
三.多线程

1.多线程入门

知识点:

  • 线程含义: 进程中 执行代码的 一个分支 (一个进程至少有一个线程)
  • 线程作用: 线程是 cpu调度的 最小单位
  • 多线程模块: threading
  • 线程类:    Thread
使用步骤:

  • 导包 : import threading
  • 创建对象 : 子线程对象 = threading.Thread(target=任务名)
  • 开启进程 : 子线程对象.start()
示例:
  1. import threading
  2. # 任务1
  3. def dance():
  4.     for i in range(5):
  5.         print('跳舞',i)
  6. # 任务2
  7. def sing():
  8.     for i in range(5):
  9.         print('唱歌',i)
  10. # 多任务
  11. if __name__ == '__main__':
  12.     # 1.创建子线程对象
  13.     t1 = threading.Thread(target=dance)
  14.     t2 = threading.Thread(target=sing)
  15.     # 2.开启线程
  16.     t1.start()
  17.     t2.start()
复制代码
2.多线程的传参

知识点:
args: 以元组方式传参   注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
kwargs: 以字典方式传参  注意:需要{k:v}形式传参,k必须和任务的形参名一致
与多进程一模一样
示例:
  1. import threading
  2. """
  3. args: 以元组方式传参   注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
  4. kwargs: 以字典方式传参  注意:需要{k:v}形式传参,k必须和任务的形参名一致
  5. """
  6. # 任务1
  7. def dance(num):
  8.     for i in range(num):
  9.         print('跳舞', i)
  10. # 任务2
  11. def sing(num):
  12.     for i in range(num):
  13.         print('唱歌', i)
  14. # 多任务
  15. if __name__ == '__main__':
  16.     # 1.创建子线程对象
  17.     t1 = threading.Thread(target=dance,args=(5,))
  18.     t2 = threading.Thread(target=sing,kwargs={'num':5})
  19.     # 2.开启线程
  20.     t1.start()
  21.     t2.start()
复制代码
3.多线程注意事项


  • 多线程是在一个进程中
  1. import os
  2. import threading
  3. """
  4. args: 以元组方式传参   注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
  5. kwargs: 以字典方式传参  注意:需要{k:v}形式传参,k必须和任务的形参名一致
  6. """
  7. # 任务1
  8. def dance(num):
  9.     print(f'dance子线程中当前进程pid:{os.getpid()}')
  10.     for i in range(num):
  11.         print('跳舞', i)
  12. # 任务2
  13. def sing(num):
  14.     print(f'sing子线程中当前进程pid:{os.getpid()}')
  15.     for i in range(num):
  16.         print('唱歌', i)
  17. # 多任务
  18. if __name__ == '__main__':
  19.     print(f'main主线程中当前进程pid:{os.getpid()}')
  20.     # 1.创建子线程对象
  21.     t1 = threading.Thread(target=dance,args=(5,))
  22.     t2 = threading.Thread(target=sing,kwargs={'num':5})
  23.     # 2.开启线程
  24.     t1.start()
  25.     t2.start()
复制代码
2. 多线程是可以共享全局变量
  1. import threading
  2. mylist = []
  3. # 写
  4. def write():
  5.     global mylist
  6.     mylist = [1,2,3,4,5]
  7.     print('write:',mylist) # [1, 2, 3, 4, 5]
  8. # 读
  9. def read():
  10.     global mylist
  11.     print('read:',mylist)  # [1, 2, 3, 4, 5] 访问到了write线程修改后的内容说明多线程共享全局变量
  12. if __name__ == '__main__':
  13.     # 1.创建线程对象
  14.     t1 = threading.Thread(target=write)
  15.     t2 = threading.Thread(target=read)
  16.     # 2.开启线程
  17.     t1.start()
  18.     t2.start()
复制代码
3. 主线程默认等待子线程结束再结束
  1. import threading
  2. import time
  3. # 任务
  4. def task():
  5.     for i in range(10):
  6.         print('任务进行中...')
  7.         time.sleep(0.2)
  8. # 多任务
  9. if __name__ == '__main__':
  10.     # 1.创建线程对象
  11.     t = threading.Thread(target=task)
  12.     # 2.开启线程
  13.     t.start()
  14.     # 3.为了效果明显点,主线程等待0.5秒
  15.     time.sleep(0.5)
  16.     print('主线程中最后一行代码....')
复制代码
4. 多线程是无序的
  1. import threading
  2. import time
  3. # 任务
  4. def show():
  5.     time.sleep(1)
  6.     print(threading.current_thread().name)
  7. # 多任务
  8. if __name__ == '__main__':
  9.     for _ in range(5):
  10.         # 创建线程对象
  11.         p = threading.Thread(target=show)
  12.         # 开启线程
  13.         p.start()
复制代码
4.设置守护主线程

知识点:
  1. 方式1: daemon属性        t.daemon = True       daemon/ˈdiːmən/守护进程
  2.    
  3. 方式2: setDaemon()方法   t.setDaemon(True)
复制代码
一个是属性,一个是方法,用哪个都可以
示例:
  1. import threading
  2. import time
  3. # 任务
  4. def task():
  5.     for i in range(10):
  6.         print('任务进行中...')
  7.         time.sleep(0.2)
  8. # 多任务
  9. if __name__ == '__main__':
  10.     # 1.创建线程对象
  11.     t = threading.Thread(target=task)
  12.    
  13.     # 方式1: daemon属性
  14.     # t.daemon = True
  15.     # 方式2: setDaemon()方法
  16.     t.setDaemon(True)
  17.     # 2.开启线程
  18.     t.start()
  19.     # 3.为了效果明显点,主线程等待0.5秒
  20.     time.sleep(0.5)
  21.     print('主线程中最后一行代码....')
复制代码
5.获取当前线程信息

知识点:

  • 获取当前线程对象:threading.current_thread()
  • 获取当前线程name:threading.current_thread().name
  • 获取当前线程id:threading.current_thread().native_id
示例:
  1. import threading
  2. def dance():
  3.     print(f'dance当前线程对象:{threading.current_thread()}')
  4.     print(f'dance当前线程name:{threading.current_thread().name}')
  5.     print(f'dance当前线程id:{threading.current_thread().native_id}')
  6. def sing():
  7.     print(f'sing当前线程对象:{threading.current_thread()}')
  8.     print(f'sing当前线程name:{threading.current_thread().name}')
  9.     print(f'sing当前线程id:{threading.current_thread().native_id}')
  10. if __name__ == '__main__':
  11.     print(f'main当前线程对象:{threading.current_thread()}')
  12.     print(f'main当前线程name:{threading.current_thread().name}')
  13.     print(f'main当前线程id:{threading.current_thread().native_id}')
  14.     # 1.创建线程对象
  15.     t1 = threading.Thread(target=dance,name='DanceThread')
  16.     t2 = threading.Thread(target=sing,name='SingThread')
  17.     # 2.开启线程
  18.     t1.start()
  19.     t2.start()
复制代码
6.线程安全问题

1. 出现的线程安全问题:
  1. import threading
  2. sum = 0
  3. def sum1():
  4.     global sum
  5.     for i in range(1000000):
  6.         sum += 1
  7.     print(sum) # 1114834
  8. def sum2():
  9.     global sum
  10.     for i in range(1000000):
  11.         sum += 1
  12.     print(sum)  # 1339347
  13. # 单任务不会出现问题 正常结果  1000000 2000000
  14. # 多任务出现了问题
  15. if __name__ == '__main__':
  16.     # 1.创建线程对象
  17.     t1 = threading.Thread(target=sum1)
  18.     t2 = threading.Thread(target=sum2)
  19.     # 2.开启线程
  20.     t1.start()
  21.     t2.start()
复制代码
2. 锁机制解决线程安全问题:
  1. import threading
  2. sum = 0
  3. def sum1(lock):
  4.     lock.acquire() # 加锁
  5.     global sum
  6.     for i in range(1000000):
  7.         sum += 1
  8.     print(sum) # 1000000
  9.     lock.release() # 释放锁
  10. def sum2(lock):
  11.     lock.acquire()  # 加锁
  12.     global sum
  13.     for i in range(1000000):
  14.         sum += 1
  15.     print(sum)  # 2000000
  16.     lock.release()  # 释放锁
  17. # 单任务不会出现问题 正常结果  1000000 2000000
  18. # 多任务出现了问题 ,利用锁机制解决问题
  19. if __name__ == '__main__':
  20.     # 创建一个锁,保证两个任务用的是同一个锁
  21.     lock= threading.Lock()
  22.     # 1.创建线程对象
  23.     t1 = threading.Thread(target=sum1,args=(lock,))
  24.     t2 = threading.Thread(target=sum2,args=(lock,))
  25.     # 2.开启线程
  26.     t1.start()
  27.     t2.start()
复制代码
3. join解决线程安全问题:
  1. import threading
  2. sum = 0
  3. def sum1():
  4.     global sum
  5.     for i in range(1000000):
  6.         sum += 1
  7.     print(sum)  # 1000000
  8. def sum2():
  9.     global sum
  10.     for i in range(1000000):
  11.         sum += 1
  12.     print(sum)  # 2000000
  13. # 学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
  14. # 单任务不会出现问题 正常结果  1000000 2000000
  15. # 多任务出现了问题 ,利用join解决问题
  16. if __name__ == '__main__':
  17.     # 1.创建线程对象
  18.     t1 = threading.Thread(target=sum1)
  19.     t2 = threading.Thread(target=sum2)
  20.     # 2.开启线程
  21.     t1.start()
  22.     t1.join()  # t1线程告诉其他线程等我执行完,你们其他线程再执行
  23.     t2.start()
复制代码
四.进程和线程对比

关系

  • 线程是依附在进程里面的,没有进程就没有线程
  • 一个进程默认提供一条线程,进程可以创建多个线程
区别

  • 进程之间不共享全局变量
  • 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法是互斥锁或者线程同步
  • 创建进程的资源开销要比创建线程的资源开销要大
  • 进程是操作系统 资源分配 的基本单位,线程是 CPU调度 的基本单位
  • 线程不能够独立执行,必须依存在进程中
  • 多进程开发比单进程多线程开发稳定性要强
优缺点
进程优缺点:
优点:可以用多核
缺点:资源开销大
线程优缺点:
优点:资源开销小
缺点:不能使用多核

来源:https://www.cnblogs.com/python1111/p/17128261.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具