import time,threading
print("=======串行方式、并行两种方式调用run()函数=======")
def run():
print('哈哈哈')
#串行
for i in range(5):
run()
#并行
for i in range(5):
t = threading.Thread(target=run) #实例化了一个线程
t.start()
print("======串行、并行方式统计网页下载时间=======")
import requests
#定义函数,用于发送http请求,获取网页的内容并写入文件
data= {}
def down_html(file_name,url):
start_time = time.time()
res = requests.get(url).content
open(file_name+'.html','wb').write(res)
end_time = time.time()
run_time = end_time-start_time
data[url] = run_time
#定义一个字典,存放要请求的url地址
urls = {
'besttest':'http://www.besttest.cn',
'niuniu':'http://www.nnzhp.cn',
'dsx':'http://www.imdsx.cn',
'cc':'http://www.cc-na.cn'
}
#串行方式下载网页
start_time = time.time()
for k,v in urls.items():
down_html(k,v)
end_time = time.time()
run_time = end_time - start_time
print('串行方式下载总共花时间:',run_time)
#并行方式下载网页
threads = []
start_time = time.time()
for k,v in urls.items(): #开启5个子线程,加上进程中有一个默认的主线程,一共是6个线程
t = threading.Thread(target=down_html,args=(k,v)) #多线程的函数如果传参的话,必须得用args
t.start()
threads.append(t)
for t in threads:
#1、主线程等待5个子线程执行完毕,主线程接着运行主线程剩余余部分的代码,
#2、不加上下面这行代码,则统计的子线程下载时间不对,下载时间取花费时间最长的那个子线程
#3、如果子线程已经运行完毕,调用下方join()方法也不会报错
t.join()
end_time = time.time()
run_time = end_time - start_time
print('并行方式下载总共花时间:',run_time)
print('并行方式各个网页下载花时间:',data)
print("=========守护线程=========")
def cry():
time.sleep(3)
print('哇哇哇.......')
for i in range(3):
t = threading.Thread(target=cry)
#1、守护线程:只要主线程结束,那么子线程立即结束,不管子线程有没有运行完成。
#2、setDaemon(True)方法把子线程设置成为守护线程
#3、如何避免由于主线程代码运行完毕,而导致子线程*也结束运行的问题:在主线程代码部分time.sleep(3),sleep的时间大于3更好
#4、去掉主线程部分的time.sleep(3)代码,如果主线程运行的比子线程快,则会导致子线程运行过程中突然中断
t.setDaemon(True)
t.start()
print('Done,运行完成。')
time.sleep(3)
print("========线程锁==========")
#线程为什么要加锁:多线程时,保证修改共享数据时有序的修改,不会产生数据修改混乱
#在python2里面需要程序员手动加锁,python3里面不加锁也无所谓,默认会自动帮你加锁。
num = 1
lock = threading.Lock() #申请一把锁
def update():
time.sleep(1)
global num
lock.acquire() #加锁
num+=1
lock.release() #解锁
ts = []
for i in range(3):
t = threading.Thread(target=update)
t.start()
ts.append(t)
[t.join() for t in ts]
print('多线程修改全局变量,修改后的值为:',num)
print("==========多进程=========")
import multiprocessing,threading
def output():
print('呵呵呵哈哈哈嘿嘿嘿')
def execute(num):
for i in range(num):
t = threading.Thread(target=output)
t.start()
if __name__ == '__main__':
for i in range(5):
p = multiprocessing.Process(target=execute,args=(2,)) #启动5个进程,6个线程
p.start()
# 问题:为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快
# 原因:因为GIL,python只有一个GIL,运行python时,就要拿到这个锁才能执行,在遇到I/O 操作时会释放这把锁。
# 如果是纯计算的程序,没有 I/O 操作,解释器会每隔100次操作就释放这把锁,让别的线程有机会 执行(这个次数可以通sys.setcheckinterval
# 来调整)同一时间只会有一个获得GIL线程在跑,其他线程都处于等待状态
# 1、如果是CPU密集型代码(循环、计算等),由于计算工作量多和大,计算很快就会达到100,然后触发GIL的释放与在竞争,多个线程来回切换损耗资源,
# 所以在多线程遇到CPU密集型代码时,单线程会比较快
# 2、如果是I\O密集型代码(文件处理、网络爬虫),开启多线程实际上是并发(不是并行),IO操作会进行IO等待,线程A等待时,自动切换到线程B,
# 这样就提升了效率