进程和线程理解
1、线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位
2、一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
3、进程之间相互独立,但一个进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程中不可见。
4、调度和切换:线程上下文切换比进程上下文切花要快的多
下面给出一个示例
import threading
import time
def test(x):
print(x)
time.sleep(2)
t1 = threading.Thread(target=test,args=(1,)) #创建一个线程
t2 = threading.Thread(target=test,args=(2,))
t1.start()
t2.start()
class MyThread(threading.Thread):
def __init__(self,n):
super(MyThread, self).__init__()
self.n = n
def run(self):
print("以类的方式创建多线程",self.n)
m1 = MyThread(111)
m2 = MyThread(222)
m1.start()
m2.start()
线程的特性
1、守护线程
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
2、线程中的一些方法
join方法
这个方法的意义是,当该线程使用这个方法时,如果该线程没有完成,则其他的线程必须要等到这个线程结束之后才能够开始
current_thread方法
查看我们当前运行的是什么线程
active_count方法
这个方法可以查看当前存活、活动着的线程数量
下面给出例子
import threading
import time
def run(x):
print(f"线程{x}")
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
res = [] #字典方便存放数据
for i in range(50):
# if i == 9:
# i = 2
t = threading.Thread(target=run,args=(i,))
t.setDaemon(True) #守护线程
t.start()
res.append(t) #将线程添加到字典中
# 查看活动的线程
print(threading.active_count())
for t in res: #遍历字典中的线程
t.join()
# t1 = threading.Thread(target=run,args=(1,))
# t2 = threading.Thread(target=run, args=(2,))
# t1.start()
# t1.join() #等待一个线程结束用join函数
# t2.start()
# for i in range(50):
# t = threading.Thread(target=run,args=(i,))
# t.start()
# end_time = time.time()
#
#
# #1970年到现在总共走了多少秒
# print(time.time())
#
# # run(1)
# # run(2)
print(f"程序共运行了{time.time()-start_time}秒")
#查看当前线程
print(threading.current_thread())
这里存活的线程有51个是因为,MyThread也是一个线程,是主线程,上面有50个线程,相加为51.
线程锁
线程锁是线程安全中十分重要的一个环节,如果没有线程锁会发生,两个线程互相抢占CPU资源,一个线程对全局变量做了++操作之后,还没来得及比较输出操作,另一个线程抢占CPU,进行比较打印输出,造成一些影响。
下面给出一个示例
import threading
def run():
global x
lock.acquire() #申请一把锁
x +=1
lock.release() #释放一把锁
if __name__=='__main__':
x = 0
res = []
lock = threading.Lock() #实例化线程锁
for i in range(100):
t = threading.Thread(target=run,args=())
t.start()
res.append(t)
for t in res:
t.join()
print(x)
递归锁
当有多把锁的时候,是无法很好的判断出要释放哪个锁,所以会出现线程卡死的现象,这种情况下,就需要我们的嵌套锁了
嵌套锁的概念
给出个示例
import threading
def run1():
global x
lock.acquire() # 申请一把锁,锁2
x +=1
lock.release() # 释放一把锁,锁2
return x
def run2():
global y
lock.acquire() # 申请一把锁
y += 1
lock.release() # 释放一把锁
return y
def run3():
lock.acquire() # 申请一把锁,锁1
res1 = run1()
res2 = run2()
lock.release() # 释放一把锁,锁1
print(res1,res2)
if __name__=='__main__':
x = 0
y = 0
lock = threading.RLock() #嵌套锁
for i in range(50):
t = threading.Thread(target=run3)
t.start()
while threading.active_count() != 1: # 当有子线程在运行的时候,就不向下走,等线程都结束,再继续向下走
print(f'正在运行{threading.active_count()}个线程')
print('程序运行结束')