一.调用多线程工具
1.将线程需要做的事情写入到函数中
import threadingdef task(arg):passt = threading.Thread(target=task,args=('xxx',)) # 实例化一个对象,传递函数名和参数t.start() # 用子线程执行task函数
2.将线程需要做的事情写入到对象的run()方法中
示例1:
import threadingclass MyThread(threading.Thread):def run(self):print('执行此线程', self._args)t = MyThread(args=(100,))t.start()
示例2:
import requestsimport threadingclass DouYinThread(threading.Thread):def run(self):file_name, video_url = self._argsres = requests.get(video_url)with open(file_name, mode='wb') as f:f.write(res.content)url_list = [("东北F4模仿秀.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"),("卡特扣篮.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"),("罗斯mvp.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg")]for item in url_list:t = DouYinThread(args=(item[0], item[1]))t.start()
二.多线程的常见方法
1.t.start() 线程准备就绪(等待CPU进行调度,具体时间由CPU来决定)
import threadingloop = 10000000number = 0def _add(count):global numberfor i in range(count):number += 1t = threading.Thread(target=_add,args=(loop,))t.start() # 这里主线程不会等待子线程,而是直接进入后面的代码,进行printprint(number)
2.t.join() 等待当前线程任务执行完毕后,再继续向下执行
import threadingnumber = 0def _add():global numberfor i in range(10000000):number += 1t = threading.Thread(target=_add)t.start()t.join() # 主线程等待中...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’)
<a name="c7ssG"></a>#### 4.线程名称的设置与获取```pythonimport threadingdef task(arg):# 获取当前执行此代码的线程name = threading.current_thread().getName()print(name)for i in range(10):t = threading.Thread(target=task, args=(11,))t.setName('日魔-{}'.format(i))t.start()
三.线程安全与线程锁
1.当面临两个线程执行同一个函数或者两个线程操作同一个变量时,会出现数据错误
两个线程操作同一个数据:globa number
import threadingloop = 10000000number = 0def _add(count):global numberfor i in range(count):number += 1def _sub(count):global numberfor i in range(count):number -= 1t1 = threading.Thread(target=_add, args=(loop,))t2 = threading.Thread(target=_sub, args=(loop,))t1.start()t2.start()t1.join() # t1线程执行完毕,才继续往后走t2.join() # t2线程执行完毕,才继续往后走print(number)
两个线程操作同一个函数:
import threadingnum = 0def task():global numfor i in range(1000000):num += 1print(num)for i in range(2):t = threading.Thread(target=task)t.start()
2.启用线程锁:当这个线程执行完成,开锁,关锁,其他线程才能进来
两个操作同一个变量的函数用同一套锁:
import threadinglock_object = threading.RLock()loop = 10000000number = 0def _add(count):lock_object.acquire() # 加锁global numberfor i in range(count):number += 1lock_object.release() # 释放锁def _sub(count):lock_object.acquire() # 申请锁(等待)global numberfor i in range(count):number -= 1lock_object.release() # 释放锁t1 = threading.Thread(target=_add, args=(loop,))t2 = threading.Thread(target=_sub, args=(loop,))t1.start()t2.start()t1.join() # t1线程执行完毕,才继续往后走t2.join() # t2线程执行完毕,才继续往后走print(number)
这个函数本身加一把锁:
import threadingnum = 0lock_object = threading.RLock()def task():print("开始")lock_object.acquire() # 第1个抵达的线程进入并上锁,其他线程就需要再此等待。global numfor i in range(1000000):num += 1lock_object.release() # 线程出去,并解开锁,其他线程就可以进入并执行了print(num)for i in range(2):t = threading.Thread(target=task)t.start()
3.线程锁可以基于上下文进行管理:
import threadingnum = 0lock_object = threading.RLock()def task():print("开始")with lock_object: # 基于上下文管理,内部自动执行 acquire 和 releaseglobal numfor i in range(1000000):num += 1print(num)
4.默认线程安全的数据
