一.调用多线程工具

1.将线程需要做的事情写入到函数中

  1. import threading
  2. def task(arg):
  3. pass
  4. t = threading.Thread(target=task,args=('xxx',)) # 实例化一个对象,传递函数名和参数
  5. t.start() # 用子线程执行task函数

2.将线程需要做的事情写入到对象的run()方法中

示例1:

  1. import threading
  2. class MyThread(threading.Thread):
  3. def run(self):
  4. print('执行此线程', self._args)
  5. t = MyThread(args=(100,))
  6. t.start()

示例2:

  1. import requests
  2. import threading
  3. class DouYinThread(threading.Thread):
  4. def run(self):
  5. file_name, video_url = self._args
  6. res = requests.get(video_url)
  7. with open(file_name, mode='wb') as f:
  8. f.write(res.content)
  9. url_list = [
  10. ("东北F4模仿秀.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"),
  11. ("卡特扣篮.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"),
  12. ("罗斯mvp.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg")
  13. ]
  14. for item in url_list:
  15. t = DouYinThread(args=(item[0], item[1]))
  16. t.start()

二.多线程的常见方法

1.t.start() 线程准备就绪(等待CPU进行调度,具体时间由CPU来决定)

  1. import threading
  2. loop = 10000000
  3. number = 0
  4. def _add(count):
  5. global number
  6. for i in range(count):
  7. number += 1
  8. t = threading.Thread(target=_add,args=(loop,))
  9. t.start() # 这里主线程不会等待子线程,而是直接进入后面的代码,进行print
  10. print(number)

2.t.join() 等待当前线程任务执行完毕后,再继续向下执行

  1. import threading
  2. number = 0
  3. def _add():
  4. global number
  5. for i in range(10000000):
  6. number += 1
  7. t = threading.Thread(target=_add)
  8. t.start()
  9. t.join() # 主线程等待中...
  10. print(number)

3.t.setDaemon(True/False),守护线程(必须放在start之前)

  • t.setDaemon(True),设置为守护线程,主线程执行完毕后,子线程也自动关闭。
  • t.setDaemon(False),设置为非守护线程,主线程等待子线程,子线程执行完毕后,主线程才结束。(默认) ```python import threading import time

def task(arg): time.sleep(5) print(‘任务’)

t = threading.Thread(target=task, args=(11,)) t.setDaemon(True) # True/False t.start()

print(‘END’)

  1. <a name="c7ssG"></a>
  2. #### 4.线程名称的设置与获取
  3. ```python
  4. import threading
  5. def task(arg):
  6. # 获取当前执行此代码的线程
  7. name = threading.current_thread().getName()
  8. print(name)
  9. for i in range(10):
  10. t = threading.Thread(target=task, args=(11,))
  11. t.setName('日魔-{}'.format(i))
  12. t.start()

三.线程安全与线程锁

1.当面临两个线程执行同一个函数或者两个线程操作同一个变量时,会出现数据错误

两个线程操作同一个数据:globa number

  1. import threading
  2. loop = 10000000
  3. number = 0
  4. def _add(count):
  5. global number
  6. for i in range(count):
  7. number += 1
  8. def _sub(count):
  9. global number
  10. for i in range(count):
  11. number -= 1
  12. t1 = threading.Thread(target=_add, args=(loop,))
  13. t2 = threading.Thread(target=_sub, args=(loop,))
  14. t1.start()
  15. t2.start()
  16. t1.join() # t1线程执行完毕,才继续往后走
  17. t2.join() # t2线程执行完毕,才继续往后走
  18. print(number)

两个线程操作同一个函数:

  1. import threading
  2. num = 0
  3. def task():
  4. global num
  5. for i in range(1000000):
  6. num += 1
  7. print(num)
  8. for i in range(2):
  9. t = threading.Thread(target=task)
  10. t.start()

2.启用线程锁:当这个线程执行完成,开锁,关锁,其他线程才能进来

两个操作同一个变量的函数用同一套锁:

  1. import threading
  2. lock_object = threading.RLock()
  3. loop = 10000000
  4. number = 0
  5. def _add(count):
  6. lock_object.acquire() # 加锁
  7. global number
  8. for i in range(count):
  9. number += 1
  10. lock_object.release() # 释放锁
  11. def _sub(count):
  12. lock_object.acquire() # 申请锁(等待)
  13. global number
  14. for i in range(count):
  15. number -= 1
  16. lock_object.release() # 释放锁
  17. t1 = threading.Thread(target=_add, args=(loop,))
  18. t2 = threading.Thread(target=_sub, args=(loop,))
  19. t1.start()
  20. t2.start()
  21. t1.join() # t1线程执行完毕,才继续往后走
  22. t2.join() # t2线程执行完毕,才继续往后走
  23. print(number)

这个函数本身加一把锁:

  1. import threading
  2. num = 0
  3. lock_object = threading.RLock()
  4. def task():
  5. print("开始")
  6. lock_object.acquire() # 第1个抵达的线程进入并上锁,其他线程就需要再此等待。
  7. global num
  8. for i in range(1000000):
  9. num += 1
  10. lock_object.release() # 线程出去,并解开锁,其他线程就可以进入并执行了
  11. print(num)
  12. for i in range(2):
  13. t = threading.Thread(target=task)
  14. t.start()

3.线程锁可以基于上下文进行管理:

  1. import threading
  2. num = 0
  3. lock_object = threading.RLock()
  4. def task():
  5. print("开始")
  6. with lock_object: # 基于上下文管理,内部自动执行 acquire 和 release
  7. global num
  8. for i in range(1000000):
  9. num += 1
  10. print(num)

4.默认线程安全的数据

![@~NKMUII@4NQUP~JCIH43R.png
要多注意看一些开发文档中是否标明线程安全

5.同步锁与递归锁

单次效率同步锁比递推锁高,同步只能锁一次,递归可以锁多次

  1. import threading
  2. lock_object = threading.Lock()
  3. lock_object = threading.RLock()

递归锁,引用在,后续函数在前面函数基础上添加功能又做成函数时,需要加锁

  1. import threading
  2. lock = threading.RLock()
  3. # 程序员A开发了一个函数,函数可以被其他开发者调用,内部需要基于锁保证数据安全。
  4. def func():
  5. with lock:
  6. pass
  7. # 程序员B开发了一个函数,可以直接调用这个函数。
  8. def run():
  9. print("其他功能")
  10. func() # 调用程序员A写的func函数,内部用到了锁。
  11. print("其他功能")
  12. # 程序员C开发了一个函数,自己需要加锁,同时也需要调用func函数。
  13. def process():
  14. with lock:
  15. print("其他功能")
  16. func() # ----------------> 此时就会出现多次锁的情况,只有RLock支持(Lock不支持)。
  17. print("其他功能")

四、线程池