# print(lst)
for i in lst:
i.join()
endtime = time.time()
print("运行的时间是{}".format(endtime - startime) ) # 运行的时间是1.8805944919586182
#多进程速度
if name == “__main__”:
lst = []
startime = time.time()
for i in range(10000):
p = Process(target=func,args=(i,))
p.start()
lst.append§
# print(lst)
for i in lst:
i.join()
endtime = time.time()
print(“运行的时间是{}”.format(endtime - startime) ) # 运行的时间是101.68004035949707
多进程:1000个进程耗时9.06秒
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8db24f608da644fcb4316a8e502a5daa.png)
多线程:多线程之间,数据共享,可以直接操作数据。1000个线程耗时0.087秒,差距巨大,所以对于IO密集型,还是用多线程较快
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fbcd8d9305a24115b9ff034df176b707.png)
多进程执行计算密集型,如果各个进程间各计算各的,不用共享数据,由于可以使用多核,比多线程快。
如果是各个进程间数据共享,同步计算最终结果,多进程反而非常慢,远远慢于多线程
#(3) 多线程之间,数据共享
num = 100
lst = []
def func():
global num
num -= 1
for i in range(100):
t = Thread(target=func)
t.start()
lst.append(t)
for i in lst:
i.join()
print(num)
多线程之间共享数据,可以直接操作
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9c8584e5116346debc7254d4a8d022f6.png)
## 2、自定义线程类
#用类定义线程,必须手动调用父类\_\_init\_\_方法,必须重载父类run方法,定义自己线程类逻辑
from threading import Thread
import os,time
### (1)必须继承父类Thread,来自定义线程类
class MyThread(Thread):
def \_\_init\_\_(self,name):
# 手动调用父类的构造方法
super().__init__()
# 自定义当前类需要传递的参数
self.name = name
def run(self):
print( "当前进程号{},name={}".format(os.getpid() , self.name) )
if name == “__main__”:
t = MyThread(“我是线程”)
t.start()
print( “当前进程号{}”.format(os.getpid()) )
新版:
#自定义线程类
from threading import Thread,current_thread
(1)必须继承父类Thread,来自定义线程类
class MyThread(Thread):
def __init__(self,name):
# 手动调用父类的构造方法
super().init()
# 自定义当前类需要传递的参数
self.name = name
def run(self):
print(f"当前线程的线程号是{current\_thread().ident}")
if name == ‘__main__’:
for i in range(10):
t = MyThread(f"线程{i}")
t.start()
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/aa250878ae74446db4ba69113ca78ac8.png)
### (2)线程中的相关属性
线程.is_alive() 检测线程是否仍然存在
线程.setName() 设置线程名字
线程.getName() 获取线程名字
1.currentThread().ident 查看线程id号 新版用current_thread().ident
2.enumerate() 返回目前正在运行的线程列表
3.activeCount() 返回目前正在运行的线程数量
getName,setName被弃用了
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c36081fcd4c6402a8863b8ae58537dca.png)
新版:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f087bfcb38604e6fb066595b173211ba.png)
def func():
time.sleep(1)
if name == “__main__”:
t = Thread(target=func)
t.start()
# 检测线程是否仍然存在
print( t.is_alive() )
# 线程.getName() 获取线程名字
print(t.getName())
# 设置线程名字
t.setName(“抓API接口”)
print(t.getName())
from threading import currentThread
from threading import enumerate
from threading import activeCount
def func():
time.sleep(0.1)
print(“当前子线程号id是{},进程号{}”.format( currentThread().ident ,os.getpid()) )
if name == “__main__”:
t = Thread(target=func)
t.start()
print(“当前主线程号id是{},进程号{}”.format( currentThread().ident ,os.getpid()) )
for i in range(5):
t = Thread(target=func)
t.start()
# 返回目前正在运行的线程列表
lst = enumerate()
print(lst,len(lst))
# 返回目前正在运行的线程数量 (了解)
print(activeCount())
新版:
### 线程中的相关属性
import time
from threading import Thread,current_thread
from threading import enumerate
from threading import active_count
def func():
time.sleep(1)
print(f"当前子线程的线程号{current_thread().ident}")
if name == ‘__main__’:
for i in range(5):
t = Thread(target=func)
t.start()
#设置线程名
t.name = f"抓API接口{i}"
# 返回目前正在运行的线程列表
lst = enumerate()
print(lst,len(lst))
# 返回目前正在运行的线程数量 (了解)
print(active_count())
当前运行线程数量,一个主线程,5个子线程
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8b5a281e31af41b0a33393f0b6ad32ce.png)
## 3、守护线程
等待所有线程全部执行完毕之后,自己再终止程序,守护所有线程
from threading import Thread
import time
def func1():
while True:
time.sleep(1)
print(“我是函数func1”)
def func2():
print("我是func2 start … ")
time.sleep(3)
print("我是func2 end … ")
def func3():
print("我是func3 start … ")
time.sleep(6)
print("我是func3 end … ")
if name == “__main__”:
t = Thread(target=func1)
t2 = Thread(target=func2)
t3 = Thread(target=func3)
# 设置守护线程 (启动前设置) 新版本该方法已弃用
t.setDaemon(True)
t.start()
t2.start()
t3.start()
print("主线程执行结束.... ")
新版本设置守护线程的setDaemon()方法已弃用,改为了通过属性设置
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/19f1cdcfd3464d8caf177f48590d4cee.png)
守护线程是等所有线程执行结束,自己再终止程序,守护所有线程
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/7233f9d97f30429b9bd423eb93a28330.png)
## 4、线程中的数据安全问题
#多线程之间共享全局变量,出现数据错误问题
import threading
#全局变量
g_sum = 0
def sum1():
for i in range(1000000):
# 不可变类型用方法修改数据,要声明为全局变量
global g_sum
g_sum += 1
print(‘sum1’, g_sum)
def sum2():
for i in range(1000000):
global g_sum
g_sum += 1
print(‘sum2’, g_sum)
if name == ‘__main__’:
sum1_thread = threading.Thread(target=sum1)
sum2_thread = threading.Thread(target=sum2)
sum1_thread.start()
sum2_thread.start()
sum1 911662
sum2 1434503
出现的结果不是2百万,由于两个线程是随机执行的,有可能几乎同时对数据进行操作,导致少加的问题
解决办法:上锁
互斥锁:
互斥锁:对共享数据进行锁定,保证同一时刻只能有一个线程去操作
注意:
互斥锁是多个线程一起去抢,抢到锁的线程先执行,没抢到锁的线程需要等待,等互斥锁使用完释放后,
其他等待的线程再去抢这个锁
线程不安全,执行结果不对
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/adbffbe1f8de4170b32ff099c4433d01.png)
多个线程可能同时操作数据,拿到的数据一样,操作后的结果不一样。造成混乱。比如几乎同时拿到1,运算需要时间,但不同线程读取得到的数据是一样的。
线程1拿到数据加1,得到2,线程2拿到数据减1,得到0
线程1往原来数据存2,线程2往原来存0,以后面放的为准,下次操作又会出现同样的混乱。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/91a6b21eb6534a9e81e740b76af9c019.png)
上锁:不同的线程采用同步计算,当一个线程运算完,才释放锁,让另一个线程运算
from threading import Thread , Lock
import time
n = 0
def func1(lock):
global n
lock.acquire()
for i in range(1000000):
n += 1
lock.release()
def func2(lock):
global n
# with语法可以简化上锁+解锁的操作,自动完成
with lock:
for i in range(1000000):
n -= 1
if name == “__main__”:
lst = []
lock = Lock()
start = time.time()
for i in range(10):
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
写在最后
在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。
需要完整版PDF学习资源私我
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。**
需要完整版PDF学习资源私我
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-byE3pdIL-1712857106319)]