0 多任务


  • 多任务:
    • 一个系统可以同时运行多个程序,则该操作系统为多任务操作系统。(Windows、mac、Android)
    • 一个程序可以同事执行多个任务,则该应用程序为多任务应用程序。
    • 默认情况下,CPU的一个核运行一个程序,但实际上会运行多个,假装多任务。
  • 并发:假的多任务。(一个CPU执行多个程序)
  • 并行:真的多任务。(每个CPU执行单个程序)
  • 实现多任务的两种方式:多线程、多进程;

1 threading(线程)


1.1 多线程

  1. # 导入threading模块
  2. import threading
  3. import time
  4. def say_hello():
  5. print('hello, Peter')
  6. time.sleep(1)
  7. if __name__ == '__main__':
  8. for i in range(5):
  9. # 创建对象
  10. t = threading.Thread(target=say_hello) # target参数为对某函数做标记,参数中的函数名不包括()
  11. # 创建线程
  12. t.start()
  1. import threading
  2. import time
  3. def task_1():
  4. for i in range(20):
  5. print('task_1 print: %s' % i)
  6. time.sleep(1)
  7. def task_2():
  8. for i in range(20):
  9. print('task_2 print: %s' % i)
  10. time.sleep(1)
  11. if __name__ == '__main__':
  12. t1 = threading.Thread(target=task_1)
  13. t2 = threading.Thread(target=task_2)
  14. t1.start()
  15. t2.start()
  16. for i in range(20):
  17. print('task_main print: %s' % i)
  18. time.sleep(1)
  19. # 该模块中,18-20执行的是主线程的打印任务,task_1和task_2微模块中的两个子线程;
  20. # 各线程执行的顺序不确定:执行代码时当前的运行环境可能不同、资源的分配可能不同,导致惨做系统调用顺序不一定一致;
  21. # task_1()或task_2()函数执行结束时,意味着其对应的线程结束;
  22. # 程序开始执行,就会有主线程调用。所有子线线程都结束主线程才会真正结束,即便18-20没有完成;

1.2 线程传参

  1. import threading
  2. import time
  3. def say_hello1(a):
  4. for i in range(10):
  5. print('hello', a)
  6. time.sleep(0.5)
  7. def say_hello2(a1, a2):
  8. for i in range(10):
  9. print(a1, 'says that hello', a2)
  10. time.sleep(0.5)
  11. def main():
  12. # ------------- <方法一> ------------- #
  13. b = threading.Thread(target=say_hello1, args=('Peter',))
  14. # args的参数为元组,单元素后要加,
  15. b.start()
  16. # ------------- <方法二> ------------- #
  17. c = threading.Thread(target=say_hello2, kwargs={'a1': 'Peter', 'a2': 'Joey'})
  18. # kwargs的参数为字典,key为字符串要带''
  19. c.start()
  20. if __name__ == '__main__':
  21. main()

1.3 线程信息

  1. import threading
  2. import time
  3. def thread_job():
  4. print('\nT1 start\n')
  5. for i in range(10): # 执行 0-9
  6. time.sleep(0.1)
  7. # print(i)
  8. print('\nT1 finish\n')
  9. def get_knowledge_of_thread():
  10. print('当前运行进程数量:%s' % threading.active_count()) # 当时同时进行几个进程
  11. print('当前运行的所有进程:%s' % threading.enumerate()) # 返回一个列表,包括所有当前进行的进程
  12. print('正在运行的线程:%s' % threading.current_thread()) # 返回正在运行的线程
  13. def main():
  14. get_knowledge_of_thread()
  15. added_thread = threading.Thread(target=thread_job, name='T1') # target的参数为函数名,且不带有()
  16. added_thread.start() # 开始线程
  17. get_knowledge_of_thread()
  18. added_thread.join() # 结束线程
  19. get_knowledge_of_thread() # 可看做所有线程成都运行结束才进行的任务
  20. if __name__ == '__main__':
  21. main()
  1. C:\Users\ASUS\AppData\Local\Programs\Python\Python38-32\python.exe C:/Users/ASUS/PycharmProjects/pythonProject/test_20220511.py
  2. 当前运行进程数量:1
  3. 当前运行的所有进程:[<_MainThread(MainThread, started 10628)>]
  4. 正在运行的线程:<_MainThread(MainThread, started 10628)>
  5. T1 start
  6. 当前运行进程数量:2
  7. 当前运行的所有进程:[<_MainThread(MainThread, started 10628)>, <Thread(T1, started 6040)>]
  8. 正在运行的线程:<_MainThread(MainThread, started 10628)>
  9. 0
  10. 1
  11. 2
  12. 3
  13. 4
  14. 5
  15. 6
  16. 7
  17. 8
  18. 9
  19. T1 finish
  20. 当前运行进程数量:1
  21. 当前运行的所有进程:[<_MainThread(MainThread, started 10628)>]
  22. 正在运行的线程:<_MainThread(MainThread, started 10628)>
  23. 进程已结束,退出代码0

1.4 互斥锁

  1. import threading
  2. import time
  3. # 定义一个全局变量,用来存储互斥锁
  4. trdl = threading.Lock() # 注意Luck首字母要大写
  5. def say_hello1(a):
  6. # 上锁
  7. trdl.acquire()
  8. for i in range(10):
  9. print('hello', a)
  10. time.sleep(0.5)
  11. # 解锁
  12. trdl.release()
  13. def say_hello2(a1, a2):
  14. # 上锁
  15. trdl.acquire()
  16. for i in range(10):
  17. print(a1, 'says that hello', a2)
  18. time.sleep(0.5)
  19. # 解锁
  20. trdl.release()
  21. def main():
  22. b = threading.Thread(target=say_hello1, args=('Peter',))
  23. b.start()
  24. c = threading.Thread(target=say_hello2, kwargs={'a1': 'Peter', 'a2': 'Joey'})
  25. c.start()
  26. if __name__ == '__main__':
  27. main()
  • 在 1.2 的基础上,加上 5/9/14/19/23 行代码,代码会分批执行,现将 say_hello1 全部执行完毕,在一口气执行完 say_hello2
  • 互斥锁的作用是在执行这段代码时,其它线程全部暂停;
  • 重复使用互斥锁 trdl.acquire 的下场就是程序陷入停顿;

9 参考

【莫烦Python】Threading 学会多线程 Python_哔哩哔哩_bilibili

Python多任务编程 1 线程_哔哩哔哩_bilibili

Python多任务编程 3 互斥锁_哔哩哔哩_bilibili