# ### Manager (list列表 , dict字典) 进程之间的共享数据(列表或者字典等)
from multiprocessing import Process,Manager,Lock
def work(data,lock):
# 1.正常写法
"""
lock.acquire()
# data["count"] -= 1
data[0] += 1
lock.release()
"""
# 2.使用with 语法简化上锁解锁操作
with lock:
data[0] += 1
if __name__ == "__main__":
m = Manager()
# 创建一个共享的字典
data = m.dict( {"count":20000} )
# 创建一个共享的列表
data = m.list([1,2,3])
# print(data)
lst = []
lock = Lock()
for i in range(100):
p = Process(target=work,args=(data,lock))
p.start()
lst.append(p)
# 确保所有的进程执行完毕,然后在向下运行,打印数据,否则报错;
for i in lst:
i.join()
print(data) # [101, 2, 3]
# 19900
# {'count': 19901}
# -----------------------------------------------------
#线程
# 进程是 划分资源 资源分配最小单位
# 线程 执行程序 是计算机中调度最小单位
# 多个线程 共享一份资源 进程
from threading import Thread
from multiprocessing import Process
import os,time
#(1) 一份进程资源中可以包含多个线程
def func(num):
print("当前线程,所归属的进程id",os.getpid(),num)
for i in range(10)
#(基于当前这个主进程创建了10个子线程,然后主线程本身就自带一个线程,一共11个)
t = Thread(target=func,args=(i,)) #创建线程跟进程对象用法一样,返回一个线程对象
t.start()
#(2) 并发的多进程和多线程,谁的速度更快
def func(num):
print("当前线程,所归属的进程id",os.getpid(),num)
if __name__ == '__main__':
#统计1000个线程的运行时间
#记录时间
starttime = time.time()
lst = []
for i in range(1000):
t = Thread(target=func,args=(i,))
t.start()
lst.append(t)
#确保所有线程执行完毕
for i in lst:
i.join()
#结束时间
endtime = time.time()
print('执行的时间是{}'.format(endtime-starttime))
#统计1000个进程的运行时间
#记录时间
starttime = time.time()
lst = []
for i in range(1000):
p = Process(target=func,args=(i,))
p.start()
lst.append(p)
#确保所有线程执行完毕
for i in lst:
i.join()
#结束时间
endtime = time.time()
print('执行的时间是{}'.format(endtime-starttime)
#(3)多线程共享同一份进程资源
num = 1000
def func():
global num
num -= 1
for i in range(1000):
t = Thread(target=func)
t.start()
print(num)
# ------------------------------------------------
# 用类去定义线程
from threading import Thread
class MyThread(Thread):
def __init__(self,name):
# 手动调用父类的构造方法
super().__init__()
self.name = name
def run(self): # 这个名字不能乱写,必须是run
print("当前进程正在执行running..",self.name)
if __name__ == "__main__": # 无论线程进程,这句话必须加上
t = MyThread("爆炸")
t.start()
print("主线程执行完毕")
# 为什么子线程比主线程执行速度要快了?因为不用额外建立空间了,没有什么阻塞,这个也是典型的异步程序. 都是异步并发
# 如果在子线程上加一个sleep,就会发现主线程先执行完毕了
# 进程是一片地,线程是这片地上的工人
# --------------------------------------------------
"""线程相关函数"""
"""
1.线程.is_alive() 检测线程是否仍然存在
2.线程.setName() 设置线程名字
3.线程.getName() 获取线程名字
4.currentThread().ident 查看线程id号
5.enumerate() 返回目前正在运行的线程列表
6.activeCount() 返回目前正在运行的线程数量
"""
from threading import Thread
def func():
pass
if __name__ == "__main__": # 无论线程进程,这句话必须加上
t = Thread(target=func)
print(t)
t.start()
print(t)
print(t.is_alive()) # False
print(t.get.Name()) # Thread-1
t.setName("alex")
print(t.getName)
# 如果加个sleep,最后会返回True,因为那时候主线程都执行完了
# 线程公用一个进程id,但每个线程也都有自己的线程id号
from threading import Thread
from threading import CurrentThread
from threading import enumerate
from threading import activeCount
import os,time
"""
def func():
print("子线程id",currentThread().ident,os.getpid())
# 子线程id 123145367060480 39988
if __name__ == "__main__": # 无论线程进程,这句话必须加上
Thread(target=func).start()
print("主线程id",currentThread().ident,os.getpid())
# 主线程id 140736045925248 39988
"""
def func():
print("子线程id",currentThread().ident,os.getpid())
time.sleep(0.5)
if __name__ == "__main__": # 无论线程进程,这句话必须加上
for i in range(10):
Thread(target = func).start()
lst = enumerate()
# 子进程10个,主进程1个,一共11个
print(lst, len(lst)) # 11
# enumerate 打印活着的线程
print(activeCount()) # 11 这是第二个方法,一般都用enumerate
print(obj)#
# enumerate 枚举 zip 拉链, 他俩返回的都是迭代器,返回的都是迭代器
# --------------------------------------------------
"""守护线程
等待所有线程全部执行完毕之后,再终止自己,它守护的是所有线程
"""
from threading import Thread
from threading import CurrentThread
from threading import enumerate
from threading import activeCount
import os,time
def func1():
while True:
time.sleep(0.5)
print("我是func1")
def func2():
print("我是func2 start")
time.sleep(3)
print("我是func2 end")
t1 = Thread(target=func1)
t2 = Thread(target=func2)
# 守护进程在start之前进行设置,主进程结束后,干掉守护的进程
# 守护线程的格式有点不一样
t1.setDaemon(True) # 主线程执行完毕后,停止t1线程的运行
t1.start()
t2.start()
print("主线程执行结束")
# 线程里面套进程,进程再套线程,资源耗费会很大
# --------------------------------------------------
"""Lock 保证线程的数据安全"""
from threading import Lock,Thread
n = 0
def func1():
global n
for i in range(1000000):
n -= 1
def func2():
global n
for i in range(1000000):
n += 1
#
# func1()
# func2()
# print(n)
if __name__ == "__main__":
lst = []
# lock = Lock() # 线程锁
for i in range(10):
t1 = Thread(target=func1)
t2 = Thread(target=func2)
t1.start()
t2.start()
lst.append(t1)
lst.append(t2)
for i in lst:
i.join()
print("主线程执行结束..",n)
"""
针对于一个线程有这么三步操作:第一步先把0取出来,第二步+1,把1算出来,第三步把计算好的值放回原空间
当有多个线程时,有可能第一个线程正在计算的过程中,还没等把结果放回去,第二个线程把0拿出来了,这就是把0拿出来了2次,造成了结果不准确.如果有更多的线程,那么就更乱了,导致数据完全不准确.
所以,针对异步处理数据,一定要加锁.加锁变成同步,即使慢,那也没办法.虽然慢,但肯定要比一个主线的同步要快
但经过实践,还是把锁放外面
"""
### 改进加锁
"""Lock 保证线程的数据安全"""
from threading import Lock,Thread
n = 0
# 加锁要加到哪个位置呢?放在循环里,上锁解锁频率变快
# 如果把锁写到外面,换锁的频率慢,如果抢到了,那就一定会把这些循环执行完才解锁,别的线程才能抢到.
# 所以还是放到里面比较好,这些线程都有机会抢到这把锁
def func1(lock):
global n
for i in range(1000000):
# 上锁方法1
lock.acquire()
n -= 1
lock.release()
def func2(lock):
global n
for i in range(1000000):
# 上锁方法2
with lock:
n += 1
#
# func1()
# func2()
# print(n)
if __name__ == "__main__":
lst = []
lock = Lock() # 线程锁
for i in range(10):
t1 = Thread(target=func1,args=(lock,))
t2 = Thread(target=func2,args=(lock,))
t1.start()
t2.start()
lst.append(t1)
lst.append(t2)
for i in lst:
i.join()
print("主线程执行结束..",n)
# ---------------
# 锁放到外面
def func1(lock):
global n
lock.acquire()
for i in range(1000000):
# 上锁方法1
n -= 1
lock.release()
def func2(lock):
global n
with lock:
for i in range(1000000):
# 上锁方法2
n += 1
#
# func1()
# func2()
# print(n)
if __name__ == "__main__":
lst = []
lock = Lock() # 线程锁
for i in range(10):
t1 = Thread(target=func1,args=(lock,))
t2 = Thread(target=func2,args=(lock,))
t1.start()
t2.start()
lst.append(t1)
lst.append(t2)
for i in lst:
i.join()
print("主线程执行结束..",n)
# --------------------------------------------------
# 信号量 Semaphore(线程)
from threading import Semaphore,Thread
import time
def func(i,sm):
with sm:
print(i)
time.sleep(3)
if __name__ == "__main__":
sm = Semaphore(5)
for i in range(20):
Thread(target=func,args=(i,sm)).start()
# 在创建线程的时候是异步创建,在执行任务的时候,因为Semaphore加了锁,所以线程之间变成了同步
# --------------------------------------------------
# 线程的缺陷:
# 线程可以并发,但是不能并行(多个cpu不停的运行多个程序),因为GIL锁(全局解释器锁,同一个进程下的多个线程,只能被一个cpu执行)
# 进程可以并发,并行执行
# 在java中,线程可以并行
# python是解释性语言,边编译边执行,不是一次性全部编译成功的,不能提前规划,都是临时调度容易造成cpu执行调度异常,所以加了一把锁叫GIL
# 想要并行的解决办法:
# 1.用多进程间接实现线程的并行
# 2.换一个Pypy,Jpython解释器
# 程序分为计算密集型和io密集型
# 对于计算密集型程序会过度依赖cpu,但网页,爬虫,oa办公,这种io密集型的程序里,python绰绰有余
python_learn Manager、线程、守护线程及相关函数
最新推荐文章于 2023-05-05 11:58:44 发布