进程线程协程

2018-10-03 17:59:25来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

进程

进程是系统进行资源分配和调度的一个独立单位,每个进程都有自己独立的内存空间,不同进程通过进程间通信来通信

线程

线程是进程的一个实体,是CPU调度和分配的基本单位,可与同属于一个进程的其他线程共享进程所拥有的全部资源

协程

协程是一种用户态的轻量级线程,协程的调度完全由用户控制

进程与线程区别

线程是指进程内的最小执行单元,也是进程内的可调度实体

  • 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,他们共享进程的地址空间,而进程有自己独立的地址空间

  • 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源

  • 二者均可并发执行

协程与线程

  • 一个线程可以有多个协程

  • 线程进程都是同步机制,协程是异步

  • 协程能保留上一次的状态,每次过程重入时,就相当于进入上一次调用的状态

 

进程线程协程在python中的作用

  • 多进程一般使用multiprocessing库,来利用多核CPU,主要用在CPU密集型的程序上,生产者消费者也可以使用。多进程的优势是一个子进程崩溃并不影响其他子进程和和主进程的运行,缺点是不能一次性启动太多进程,会严重影响系统的资源调度,特别是CPU使用率和负载

  • 多线程使用threading库,完成一些IO密集型并发操作。多线程的优势是切换快,资源消耗低,但一个线程挂掉会影响到所用线程,所以不稳定,一般使用线程池

  • 协程一般使用gevent库,多用在web方向是

  • IO密集型一般使用多线程或者多进程,CPU密集型一般使用多进程,强调非阻塞异步并发的一般使用协程

 

 

 1 import multiprocessing
 2 import time
 3 
 4 
 5 def func_1(name):
 6     print("hello", name)
 7     time.sleep(2)
 8 
 9 
10 def func_2():
11     print("你好!")
12     time.sleep(2)
13 
14 
15 pro1 = multiprocessing.Process(target=func_1, args=("gkl", ))
16 pro1.start()
17 func_2()
进程
你好!
hello gkl

 

 

 1 import multiprocessing  # 导入多进程模块
 2 
 3 
 4 mar = multiprocessing.Manager()   # 创建一个进程空间,并返回与其通信的管理器
 5 mar_list = mar.list()   # 通过管理器在服务器进程中开辟一个列表空间,并返回一个代理
 6 mar_list.append("天气不错!!!")  # 导入数据 方法和列表一致
 7 print(mar_list)
 8 
 9 
10 def sub_process(li):
11     li.append("今天星期二")
12 
13 
14 # 把代理传给子进程,子进程就可以通过这个代理来操作共享空间进行通信
15 pro = multiprocessing.Process(target=sub_process, args=(mar_list, ))
16 pro.start()  # 运行
17 pro.join()  # 阻塞  等待子进程完成后继续运行
18 print(mar_list)
进程间通信

 

['天气不错!!!']
['天气不错!!!', '今天星期二']

 

 

 1 import threading
 2 
 3 
 4 data = 0
 5 lock = threading.Lock()  # 创建一把锁  防止计算混乱  同一进程下的线程共享变量,容易发生紊乱
 6 
 7 
 8 def add():
 9     global data
10     for i in range(100000):
11         with lock:     # 锁 (加锁、释放锁)
12             data += 1
13 
14 
15 def sub():
16     global data
17     for i in range(100000):
18         with lock:
19             data -= 1
20 
21 
22 add_td = threading.Thread(target=add)
23 add_td.start()
24 sub_td = threading.Thread(target=sub)
25 sub_td.start()
26 add_td.join()
27 sub_td.join()
28 print(data)
线程间通信

运行结果为0

 

 1 import greenlet
 2 import random
 3 import time
 4 
 5 
 6 def producer():
 7     while True:
 8         item = random.randint(0, 100)
 9         print("生产了:", item)
10         con.switch(item)  # 将item传给消费者  并切换到消费者
11         time.sleep(1)
12 
13 
14 def consumer():
15     while True:
16         data = pro.switch()  # 切换到生产者  等待生产者传入item
17         print("消费了:", data)
18 
19 
20 if __name__ == '__main__':
21     pro = greenlet.greenlet(producer)  # 将一个普通函数变成协程
22     con = greenlet.greenlet(consumer)
23     con.switch()  # 运行消费者
greenlet协程通信
生产了: 35
消费了: 35
生产了: 72
消费了: 72
生产了: 4
消费了: 4
生产了: 76
消费了: 76
生产了: 61
消费了: 61
......

greenlet协程的价值

(1)高性能的原生协程

(2)语义更加明确的显式切换

(3)直接将函数包装成协程,保持原有代码风格

 

 

 1 # gevent 并发服务器
 2 import gevent
 3 from gevent import monkey; monkey.patch_socket()  # 猴子补丁  使得导入的socket都会被epoll监控
 4 import socket
 5 
 6 
 7 def response(conn):
 8     while True:
 9         data = conn.recv(1024)
10         if data == b"close":
11             conn.close()
12             break
13         else:
14             print("接收到信息:{}".format(data.decode()))
15             conn.send(data)
16 
17 
18 def run(server):
19     while True:
20         cli = server.accept()
21         gevent.spawn(response, cli[0])  # 创建一个协程
22 
23 
24 if __name__ == '__main__':
25     server = socket.socket()
26     server.bind(("0.0.0.0", 8899))
27     server.listen()
28     run(server)
gevent并发服务器
 1 # gevent 协程实现生产者消费者
 2 import gevent
 3 from gevent import monkey; monkey.patch_all()
 4 import random
 5 from gevent.queue import Queue
 6 import time
 7 
 8 
 9 def producer(que):
10     while True:
11         data = random.randint(0, 100)
12         print("生产者生产了:", data)
13         q.put(data)
14         time.sleep(1)
15 
16 
17 def consumer(que):
18     while True:
19         item = que.get()
20         print("消费者消费了:", item)
21 
22 
23 if __name__ == '__main__':
24     q = Queue()
25     pro = gevent.spawn(producer, q)
26     con = gevent.spawn(consumer, q)
27     gevent.joinall([pro, con])
gevent协程通信

 

gevent 的价值

价值一: 使用基于 epoll 的 libev 来避开阻塞

价值二: 使用基于 gevent 的 高效协程 来切换执行

价值三: 只在遇到阻塞的时候切换, 没有轮需的开销,也没有线程的开销

 

 

 

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Django商城项目笔记No.2项目准备工作

下一篇:第一个Python工程