线程
python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用。
- 线程是cpu执行的基本单元
- 线程之间的执行是无序的
- 同一进程下的线程的资源是共享的 (线程锁,互斥锁)
- 线程可以实现多任务,多用来处理I/O密集型任务
1.使用threading模块
import threading
GIL全局解释器锁
GIL:由于python的CPython解释器的原因,存在一个GIL全局解释器锁
#用来保证同一时刻只有一个线程在执行,类似于单核处理,所有说多线程并不能
#充分的利用cpu资源
threading.Thread参数介绍
#target:执行的函数
# name:设置线程的名称
#args:给执行的函数传递参数(tuple)
#kwargs:给执行的函数传递参数(dict)
#daemon:默认为Flase,主线程结束,不影响子线程执行
#daemon:为True,主线程结束,子线程结束
单线程执行
import threading
def run1(num):
for i in range(num):
print(i,threading.currentThread().name)
def run2(num):
for i in range(num):
print(i,threading.currentThread().name)
if __name__ == '__main__':
print('开始执行代吗',threading.currentThread().name)
run1()
run2()
多线程执行
import threading
def run1(num):
for i in range(num):
print(i,threading.currentThread().name)
def run2(num):
for i in range(num):
print(i,threading.currentThread().name)
if __name__ == '__main__':
print('开始执行代吗',threading.currentThread().name)
thread1 = threading.Thread(
target=run1,name='线程1',args=(100,),
kwargs={'name':'lihua'})
thread2 = threading.Thread(
target=run2, name='线程2', args=(100,),
)
thread1.start()
thread2.start()
互斥锁(重点)
threading模块中定义了Lock类,可以方便的处理锁定:
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire()
#释放
mutex.release()
线程锁的实例:
import threading
data = []
sum = 0
def run1(num,**kwargs):
# global data
global sum
print(kwargs)
lock.acquire() #加锁
for i in range(num):
print(i,threading.currentThread().name)
# data.append(i)
sum += 1
lock.release() #解锁
def run2(num):
# global data
global sum
lock.acquire()
for i in range(num):
print(i,threading.currentThread().name)
# data.append(i)
sum += 1
lock.release()
if __name__ == '__main__':
print('开支执行代码',threading.currentThread().name)
#线程锁
lock = threading.Lock()
thread1 = threading.Thread(
target=run1,name='线程1',
args=(10000,),kwargs={'name':'lihua'},
daemon=True
)
thread2 = threading.Thread(
target=run2, name='线程2',
args=(10000,),
daemon=True
)
#开启线程,执行任务
thread1.start()
thread2.start()
# join(),线程的阻塞(同步),让子线程中的任务执行完毕,
# 再回到主线程中继续执行
# thread1.join()
# thread2.join()
print(data,sum)
print('代码执行完毕', threading.currentThread().name)
自定义线程
mport threading
import requests
#threading.Thread
class CustomThread(threading.Thread):
def __init__(self,name,url):
super(CustomThread,self).__init__()
self.name = name
self.url = url
self.headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
}
def run(self):
#重点是重写run()方法,在这里写你线程执行的任务
response = requests.get(url=self.url,headers=self.headers)
print(response.status_code)
if response.status_code == 200:
with open('page.html','w') as file:
file.write(response.text)
if __name__ == '__main__':
my_thread = CustomThread(name='线程一号',url='https://www.baidu.com/')
my_thread.start()
线程池
导入模块包
from concurrent.futures import ThreadPoolExecutor
线程池中的线程需要执行的任务
def get_page_data(page):
"""
线程需要执行的任务
:param url:
:return:
"""
print(page)
return 'done下载完成'
任务执行完毕之后的回调函数,可以获取到现场执行完毕的返回值
def done(future):
print(future.result())
创建线程池,并往线程池中添加任务
#创建一个线程池
pool = ThreadPoolExecutor(10)
#如何提交任务给线程池呢?
#网线程池中添加任务
for pagenum in range(50):
#submit: 表示将我们需要执行的任务给这个线程池,
handler = pool.submit(get_page_data,pagenum)
#给线程池设置任务之后,可以设置一个回调函数,
#作用是:当我们某个任务执行完毕之后,就会回调你设置的回调函数
handler.add_done_callback(done)
pool.shutdown(wait=True)