1. 导入包 import threading
2.创建线程 thread1 = threading.Thread(tag="函数名",args=(参数,))
3.开启线程 thread1.start()
tag传递的是函数名,而不是函数的调用,需要对函数传递参数使用args,其接收的元组类型,所以当只有一个参数需要传递时,需要加上(,),保证其是元组的类型
thread.join()函数的是让主线程的子线程全部执行完再去执行主线程
import threadingdef add(lock):global totalfor i in range(1000):total += 1def desc(lock):global totalfor i in range(1000):total -= 1if __name__ == "__main__":lock = Lock()total = 0thread1 = threading.Thread(target=add)thread2 = threading.Thread(target=desc)thread1.start()thread2.start()thread1.join()thread2.join()print(total)
Lock锁的需要获取acquire锁后释放release锁才行,获取锁后,其他线程使用该锁都需要等待已获取该锁的线程释放后才能进入线程,一直等待锁的释放
lock = Lock()
lock.acqurie()后必须要lock.release(),
锁一定会影响性能
也有可能会造成死锁
“锁住”变量total
import threading
from threading import Lock,RLockdef add(lock):global totalfor i in range(1000):lock.acquire()total += 1lock.release()def desc(lock):global totalfor i in range(1000):lock.acquire()total -= 1lock.release()if __name__ == "__main__":lock = Lock()total = 0thread1 = threading.Thread(target=add,args=(lock,))thread2 = threading.Thread(target=desc,args=(lock,))thread1.start()thread2.start()print(total)
RLock锁能够在一个线程内多次获取锁,但一定要保证acquire和release的次数要对应,
rlock = RLock()
rlock.acquire()
rlock.acquire()
rlock.release()
rlock.release()
例子:
import threading
from threading import RLockdef do_something(rlock):rlock.acquire()# dorlock.release()def add(lock):global totalfor i in range(1000):lock.acquire()do_something(lock)total += 1lock.release()if __name__ == "__main__":rlock = RLock()total = 0thread1 = threading.Thread(target=add,args=(rlock,))thread1.start()print(total)
1. 导入包 import threading.Semaphore
2.控制线程数量 sem = threading.Semaphore(最大的数量)
3.开启锁 线程创建前添加锁 sem.acqurie()
4.释放锁 线程完成后释放锁 sem.release()
Semaphore是在设定的最大线程数后,每创建一个线程最大线程数就减一同时获得一个锁,当等于0时,就阻塞,等待锁的释放
import threading
import timeclass GetHtml(threading.Thread):def __init__(self,url,sem):super().__init__()self.sem = semself.url = urldef run(self):time.sleep(2)print(f'start to get html:{self.url}')self.sem.release()if __name__ == '__main__':sem = threading.Semaphore(5)for i in range(20):sem.acquire()get_html = GetHtml(url=f"url_{i}",sem=sem)get_html.start()
线程池可以获取某一个线程的状态以及该线程的返回值
1. 导入包 from concurrent.futures import ThreadPoolExecutor
2. 创建线程池对象 executor = TreadPoolExecutor(最大数量)
3. 提交线程任务 task1 = executor.submit(函数名,参数)
获取线程的状态:task1.done()
获取线程的返回值: task1.result()
取消某一线程:task2.cancel()
import time
from concurrent.futures import ThreadPoolExecutordef get_html(times):time.sleep(times)print(f"暂停{times}秒,执行成功")result = f"time is {times}"return resultif __name__ == '__main__':executor = ThreadPoolExecutor(2)task1 = executor.submit(get_html,3)task1.done()task1.result()
进阶用法
多个任务的完成,使用as_complete包或map方法,其都是返回一个生成器对象
as_complete 方法是哪个线程完成先返回
map方法是按照传递的线程返回
import time
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completeddef get_html(times):time.sleep(times)print(f"暂停{times}秒,执行成功")result = f"time is {times}"return resultif __name__ == '__main__':executor = ThreadPoolExecutor(2)times_list = [2,4,3,1]start_time = time.time()all_tasks = [executor.submit(get_html, time) for time in times_list]for future in as_completed(all_tasks):print(future.done())data = future.result()print(f"第一种方法,按照线程完成的顺序返回{data}")end_time = time.time()print(f"总计用时:{end_time - start_time}")print("==============================================")# 第二种方法start_time = time.time()for data in executor.map(get_html,times_list):print(f"第二种方法,是对应传入的顺序所返回,返回:{data}")end_time = time.time()print(f"总计用时:{end_time - start_time}")