进程、线程、协程

本文介绍了进程与线程的概念,包括并行与并发的差异,以及同步和异步的概念。详细讲解了进程间的数据共享机制,如使用Manager的字典和列表,以及Queue队列。还探讨了线程安全,展示了如何使用锁和信号量来确保数据一致性。此外,文章提到了进程池和线程池的使用,以及协程作为线程的高效替代方案。
摘要由CSDN通过智能技术生成

补充理解的知识点

  • 并行:
    • 多个cpu, 多个处理器或者是多核的处理器同时处理多个不同的任务。
  • 并发:一个cpu, 一个处理器同时处理多个任务。
    • 同步:一个任务执行完才能执行另一个任务。
    • 异步:多个任务可以并发执行。不需要等待, 切换+保存状态。

进程

    • lock.acquire()# 上锁

    • lock.release()# 解锁

    • 同一时间允许一个进程上一把锁 就是Lock

    • 加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲速度却保证了数据安全。

    • 同一时间允许多个进程上多把锁 就是[信号量Semaphore]

    • 信号量是锁的变形: 实际实现是 计数器 + 锁,同时允许多个进程上锁

    • 互斥锁Lock : 互斥锁就是进程的互相排斥,谁先抢到资源,谁就上锁改资源内容,为了保证数据的同步性

    • 注意:多个锁一起上,不开锁,会造成死锁.上锁和解锁是一对.

  • 死锁的问题解决用递归锁:
    • 死锁, 加锁没开锁
    • 递归锁: 作用就是解锁,RLock, 让noodles_lock和kuaizi_lock 都等于递归锁
      • noodles_lock = kuaizi_lock = RLock()
def func(i):
	print( "当前进程号:{} , 参数是{} ".format(os.getpid() , i)  )
	
if __name__ == "__main__":
	lst = []
	startime = time.time()
	for i in range(10000):
		p = Process(target=func,args=(i,))
		p.start()
		lst.append(p)
	# print(lst)
	for i in lst:
		i.join()
	endtime = time.time()
	print("运行的时间是{}".format(endtime - startime) ) # 运行的时间是101.68004035949707

多进程数据共享

  • Manager
# ### Manager ( list 列表  ,  dict 字典 ) 进程之间共享数据
from multiprocessing import Process , Manager ,Lock

def mywork(data,lock):
	# 共享字典
	"""
	lock.acquire()
	data["count"] -= 10
	lock.release()
	"""
	
	# 共享列表
	data[0] += 1
	
	
if __name__ == "__main__":
	lst = []
	m = Manager()
	lock = Lock()
	# 多进程中的共享字典
	# data = m.dict(  {"count":5000}  )
	# print(data , type(data) )
	# 多进程中的共享列表
	data =  m.list( [100,200,300] )
	# print(data , type(data) )
	""""""
	# 进程数超过1000,处理该数据,死机(谨慎操作)
	for i in range(10):
		p = Process(target=mywork,args=(data,lock))
		p.start()
		lst.append(p)
		
	# 必须等待子进程所有计算完毕之后,再去打印该字典,否则报错;
	for i in lst:
		i.join()
		
	print(data)
	
  • quque
from multiprocessing import Process, Queue

def test1(q):
    print(q.get())
    # print(q)
    # q.put(124)
    # q.put(test)
    q.put(123)
    return 123
# tt = test()
def test():
    return 123


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=test1, args=(q,))
    p1.start()

    q.put(test)
    p1.join()
    print(q.get())
    # q.get()

线程

def func(i):
	print( "当前进程号:{} , 参数是{} ".format(os.getpid() , i)  )

if __name__ == "__main__":
	lst = []
	startime = time.time()
	for i in range(10000):
		t = Thread(target=func,args=(i,))
		t.start()
		lst.append(t)
	# print(lst)
	for i in lst:
		i.join()
	endtime = time.time()
	print("运行的时间是{}".format(endtime - startime) ) # 运行的时间是1.8805944919586182
  • 线程间的数据安全,操作同一个数据的时候加上线程锁
from threading import Thread, Lock, Semaphore
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 lock:
        for i in range(1000000):
            n -= 1

if __name__ == '__main__':
    lock = Lock()
    lis = []
    t1 = Thread(target=func1, args=(lock, ))
    t1.start()

    t2 = Thread(target=func2, args=(lock, ))
    t2.start()

    lis.append(t1)
    lis.append(t2)
    for i in lis:
        i.join()
    print('主进程结束,打印n:{0}'.format(n))
=====》
结果: 是0 ,不加锁会出错

进程池和线程池

from concurrent.futures import ProcessPoolExecutor , ThreadPoolExecutor

"""多条进程提前开辟,可触发多cpu的并行效果"""

# (1) 进程池 ProcessPoolExecutor
def func(i, j):
	# print(i)
	time.sleep(random.uniform(0.1,0.8))
	print(" 任务执行中 ...  start ... 进程号{}".format(os.getpid()) , i )
	print(" 任务执行中 ...  end ... 进程号{}".format(os.getpid()))
	return i
	
if __name__ == "__main__":
	lst = []
	# (1) 创建进程池对象
	"""4核电脑,进程默认是4, 线程是4*5"""
	p = ProcessPoolExecutor()
	
	# (2) 异步提交任务
	"""submit(任务,参数1,参数2 ... )"""
	"""默认如果一个进程短时间内可以完成更多的任务,进程池就不会使用更多的进程来辅助完成 , 可以节省系统资源的损耗;"""
	for i in range(10):
		obj = p.submit( func , i , 1)
		# print(obj)
		# print(obj.result()) 不要写在这,导致程序同步,内部有阻塞
		lst.append(obj)
		
	# (3) 获取当前任务的返回值
	for i in lst:
		print(i.result(),">===获取返回值===?")
		
	# (4) shutdown 等待所有进程池里的进程执行完毕之后,在放行
	p.shutdown()

	print("进程池结束 ... ")
  • 进程和线程池里的map
# (3) 线程池 map
from threading import currentThread as ct
from collections import Iterator,Iterable
def func(i):
	time.sleep(random.uniform(0.1,0.7))
	print("thread ... 线程号{}".format(ct().ident),i)
	return "*" * i

if __name__ == "__main__":
	t = ThreadPoolExecutor()
	it = t.map(func,range(100))
	# 返回的数据是迭代器
	print(isinstance(it,Iterator))

	# 协调子父线程,等待线程池中所有线程执行完毕之后,在放行;
	t.shutdown()

	# 获取迭代器里面的返回值
	for i in it:
		print(i)

协程

  • 协程也叫纤程: 协程是线程的一种实现方式.

    • 指的是一条线程能够在多任务之间来回切换的一种实现.
    • 对于CPU、操作系统来说,协程并不存在.任务之间的切换会花费时间.
    • 目前电脑配置一般线程开到200会阻塞卡顿.
  • 协程的实现

    • 协程帮助你记住哪个任务执行到哪个位置上了,并且实现安全的切换
    • 一个任务一旦阻塞卡顿,立刻切换到另一个任务继续执行,保证线程总是忙碌的,更加充分的利用CPU,抢占更多的时间片
  • 一个线程可以由多个协程来实现,协程之间不会产生数据安全问题

  • 协程模块:gevent

“”“
#(1)apawm(函数,参数1,参数2,参数.…)启动协程
#(2)join阻塞,直到某个协程在任务执行完毕之后在放行
#(3)joinal1等待所有协程任务执行完毕之后放行;g1.join()g2.join()<=>gevent.joinall([gl,g2..])
#(4)value获取协程任务中的返回值gl.value g2.value rttrn from gevent import monkey;monkey.patch_all()
”“”
import gevent
import time

def eat():
    print("eat1开始吃…")
    time.sleep(1)
    print("eat2继续吃..")
    return "吃完了"

def play():
    print("play1开始玩…")
    time.sleep(1)
    print("play2继续玩…")
    return "玩完了"

# 创建协程对象g1
gl = gevent.spawn(eat)
# 创建协程对象g2
g2 = gevent.spawn(play)
# 等待所有协程任务执行完毕之后放行
gevent.joinall([gl, g2])
print("主线程执行结束.…")
# 获取协程任务中的返回值
print(g1.value)
print(g2.value)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值