Python_day7:进程、线程、协程

进程、线程、协程

一、进程与线程

  进程:程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。

  线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

  进程与线程区别:1、线程是指令集,共享内存空间,启动速度快;进程是资源的集合,至少包含一个线程,内存独立;

          2、同一进程的线程之间可以直接交流,两个进程需要通过中间代理实现;

          3、创建新的线程简单,创建新的进程需要对其父进程进行克隆;一个线程可以控制和操作同一进程的其他线程,但进程只能操作子进程;

          4、运行速度一样,无可比性。

  python threading模块:

 1 import threading,time
 2 def run(n): #定义每个线程执行的函数
 3     print("task",n)
 4     time.sleep(2)
 5 t1 = threading.Thread(target=run,args=("1",)) #生成线程实例
 6 t2 = threading.Thread(target=run,args=("2",))
 7 t1.start() #启动
 8 t2.start()
 9 print(t1.getName()) #获取线程名
10 print(t2.getName())
直接调用
 1 import threading,time
 2 class MyThread(threading.Thread):
 3     def __init__(self,n):
 4         #threading.Thread.__init__(self) #两种继承方式
 5         super(MyThread,self).__init__()
 6         self.n = n
 7     def run(self):
 8         print("task",self.n)
 9         time.sleep(2)
10 if __name__ == "__main__": #主线程的意思
11     t1 = MyThread(1)
12     t2 = MyThread(2)
13     t1.start()
14     t2.start()
继承调用

  join&daemon:

 1 import threading,time
 2 def run(n):
 3     print("task",n)
 4     time.sleep(2)
 5     print("task done.")
 6 def main():
 7     for i in range(5):
 8         t = threading.Thread(target=run, args=(i,))
 9         t.start()
10         t.join(1)
11         print('starting thread', t.getName())
12 m = threading.Thread(target=main,args=())
13 m.setDaemon(True) #将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务
14 m.start()
15 m.join(2)
16 print("---main thread done---")
join&daemon

  线程锁(互斥锁Mutex)

  Semaphore(信号量)

 1 import threading, time
 2 def run(n):
 3     semaphore.acquire()
 4     time.sleep(1)
 5     print("run the thread: %s" % n)
 6     semaphore.release()
 7 if __name__ == '__main__':
 8     num = 0
 9     semaphore = threading.BoundedSemaphore(3)  # 最多允许3个线程同时运行
10     for i in range(13):
11         t = threading.Thread(target=run, args=(i,))
12         t.start()
13 
14 while threading.active_count() != 1:
15     pass # print threading.active_count()
16 else:
17     print('----all threads done---')
semaphore

  event:通过Event来实现两个或多个线程间的交互

 1 import threading,time
 2 event = threading.Event()
 3 def lighter():
 4     count = 0
 5     event.set()
 6     while True:
 7         if count > 5 and count < 10:
 8             event.clear()
 9             print("\033[41;1m red light is on..\033[0m")
10         elif count > 10:
11             event.set()
12             count = 0
13         else:
14             print("\033[42;1m green light is on..\033[0m")
15         time.sleep(1)
16         count += 1
17 def car(name):
18     while True:
19         if event.is_set():
20             print("[%s] running.." %name)
21             time.sleep(1)
22         else:
23             print("[%s] sees red light,waiting.." %name)
24             event.wait()
25             print("\033[34;1m [%s] green light is on,start going..\033[0m" %name)
26 light = threading.Thread(target=lighter)
27 light.start()
28 car1 = threading.Thread(target=car,args=("car",))
29 car1.start()
event

   线程queue,线程之间,生产者消费者模型:解耦,使程序直接实现松耦合,提高效率

 1 queue.Queue(maxsize=0) #先入先出
 2 queue.LifoQueue(maxsize=0) #last in first out
 3 queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列
 4 Queue.qsize()
 5 Queue.empty() #return True if empty  
 6 Queue.full() # return True if full 
 7 Queue.put(item, block=True, timeout=None)
 8 Queue.put_nowait(item) #Equivalent to put(item, False)
 9 Queue.get(block=True, timeout=None)
10 Queue.get_nowait() #Equivalent to get(False).
11 Queue.task_done()
12 Queue.join() #block直到queue被消费完毕
基本方法
 1 import threading,queue,time
 2 def producer(name):
 3     count = 1
 4     while True:
 5         q.put("包子 %s" % count)
 6         print("\033[41;1m生产了包子\033[0m",count)
 7         count += 1
 8         time.sleep(0.3)
 9 def consumer(name):
10     #while q.qsize() > 0:
11     while True:
12         print("%s 取到" % name, q.get())
13         time.sleep(1)
14         #q.task_done()  # 告知这个任务执行完了
15 q = queue.Queue(maxsize=10)
16 p = threading.Thread(target=producer,args=("a",))
17 c = threading.Thread(target=consumer,args=("b",))
18 c2 = threading.Thread(target=consumer,args=("c",))
19 p.start()
20 c.start()
21 c2.start()
简单实现

  多进程:每个子进程都是由父进程启动

 1 import multiprocessing
 2 import time
 3 def f(name):
 4     time.sleep(2)
 5     print('hello', name)
 6 if __name__ == '__main__':
 7     for i in range(10):
 8         p= multiprocessing.Process(target=f, args=('bob%s'%i,))
 9         p.start()
10     #p.join()
multiprocessing

  进程Queue:进程间内存独立,实现进程间数据交换相当于复制一份数据

1 from multiprocessing import Process, Queue
2 def f(q):
3     q.put([1, None, 'hello world'])
4 if __name__ == '__main__':
5     q = Queue()
6     p = Process(target=f, args=(q,))
7     p.start()
8     print(q.get())  # prints "[42, None, 'hello']"
9     p.join()
进程Queue
 1 from multiprocessing import Process, Pipe
 2 def f(conn):
 3     conn.send([1, None, 'hello a'])
 4     print("from parent:",conn.recv())
 5     conn.close()
 6 
 7 if __name__ == '__main__':
 8     parent_conn, child_conn = Pipe()#生成实例
 9     p = Process(target=f, args=(child_conn,))
10     p.start()
11     parent_conn.send("hello ab")
12     print(parent_conn.recv())  # prints "[1, None, 'hello a']"
13     p.join()
管道Pipe
 1 from multiprocessing import Process, Manager
 2 import os
 3 def f(d, l):
 4     d[os.getpid()] = os.getpid()
 5     l.append(os.getpid())
 6     print(l)
 7 
 8 if __name__ == '__main__':
 9     with Manager() as manager:
10         d = manager.dict()
11         l = manager.list(range(5))
12         p_list = []
13         for i in range(10):
14             p = Process(target=f, args=(d, l))
15             p.start()
16             p_list.append(p)
17         for res in p_list:
18             res.join()
19 
20         print(d)
21         print(l)
进程数据共享Manager
 1 from multiprocessing import Process, Lock
 2 def f(l, i):
 3     l.acquire()
 4     print('hello world', i)
 5     l.release()
 6 
 7 if __name__ == '__main__':
 8     lock = Lock()
 9     for num in range(10):
10         Process(target=f, args=(lock, num)).start()
进程锁,保持不乱

  进程池

 1 from  multiprocessing import Process, Pool,freeze_support #windows加freeze_support
 2 import time,os
 3 def Foo(i):
 4     time.sleep(2)
 5     print("in process:",os.getpid())
 6     return i + 100
 7 def Bar(arg):
 8     print('-->exec done:', arg)
 9 if __name__ == "__main__":
10     pool = Pool(5) #同时放入5个进程
11     for i in range(10):
12         pool.apply_async(func=Foo, args=(i,), callback=Bar)#异步,callback为回调函数,由主进程执行
13         # pool.apply(func=Foo, args=(i,)) #同步
14     print('end')
15     pool.close()
16     pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
Pool

 二、协程

  协程,又称微线程,是一种用户态的轻量级线程。

  协程拥有自己的上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来时,恢复先前的寄存器上下文和栈,因此协程能保留上一次调用时的状态,每次重入时进入上次离开时逻辑流的位置。

  协程的好处:

  1. 无需上下文切换的开销;
  2. 无需原子操作和锁定的开销;
  3. 方便切换控制流,简化编程模型;
  4. 高并发,搞扩展,低成本。

   缺点:

  1. 无法运用多核资源:本质是单线程,需和进程配合才能运用到多核;
  2. 进行阻塞(blocking)时(如IO操作)会阻塞整个程序。  

  定义:

  1. 必须在只有一个单线程内实现并发;
  2. 修改共享数据无需加锁;
  3. 用户程序里自己保存多个控制流的上下文栈;
  4. 一个协程遇到IO操作自动切换到其他协程。

  Greenlet:手动switch切换

 1 from greenlet import greenlet
 2 def run1():
 3     print("1") #first
 4     g2.switch() #2
 5     print("2") #5
 6     g2.switch() #6
 7 def run2():
 8     print("3") #3
 9     g1.switch() #4
10     print("4") #7
11     
12 g1 = greenlet(run1)
13 g2 = greenlet(run2)
14 g1.switch()
15 g2.switch()
greenlet

  Gevent:遇到IO自动切换

 1 import gevent
 2 def run1():
 3     print("1")
 4     gevent.sleep(2)
 5     print("2")
 6 def run2():
 7     print("3")
 8     gevent.sleep(1)
 9     print("4")
10 
11 gevent.joinall([
12     gevent.spawn(run1),
13     gevent.spawn(run2)
14 ])
15 #输出:
16 #1
17 #3
18 #4
19 #2
gevent
 1 from urllib import request
 2 import gevent,time
 3 from gevent import monkey
 4 monkey.patch_all()#把当前程序的所有IO操作单独做上标记
 5 def f(url):
 6     print("GET:%s" %url)
 7     resp = request.urlopen(url)
 8     data = resp.read()
 9     print("%d bytes received from %s." %(len(data),url))
10 urls = [
11     "https://www.python.org/",
12     "https://www.yahoo.com/",
13     "https://www.github.com/"
14 ]
15 time_start = time.time()
16 for url in urls:
17     f(url)
18 print("同步cost:",time.time()-time_start)
19 async_time = time.time()
20 gevent.joinall([
21     gevent.spawn(f,"https://www.python.org/"),
22     gevent.spawn(f,"https://www.yahoo.com/"),
23     gevent.spawn(f,"https://www.github.com/")
24 ])
25 print("异步cost:",time.time()-async_time)
26 
27 #输出:时间与网速有关,但异步要比同步少
28 GET:https://www.python.org/
29 48845 bytes received from https://www.python.org/.
30 GET:https://www.yahoo.com/
31 501665 bytes received from https://www.yahoo.com/.
32 GET:https://www.github.com/
33 65079 bytes received from https://www.github.com/.
34 同步cost: 6.50391411781311
35 GET:https://www.python.org/
36 GET:https://www.yahoo.com/
37 GET:https://www.github.com/
38 65077 bytes received from https://www.github.com/.
39 48845 bytes received from https://www.python.org/.
40 502067 bytes received from https://www.yahoo.com/.
41 异步cost: 3.0211377143859863
同步与异步,IO自动切换

  通过Gevet实现socket并发

 1 from gevent import socket,monkey
 2 import socket,time,gevent
 3 monkey.patch_all()
 4 def server(port):
 5     s = socket.socket()
 6     s.bind(("localhost",port))
 7     s.listen()
 8     while True:
 9         conn,addr = s.accept()
10         gevent.spawn(handle_request,conn)
11 def handle_request(conn):
12     try:
13         while True:
14             data = conn.recv(1024)
15             print("recv:",data)
16             conn.send(data)
17             if not data:
18                 conn.shutdown()
19     except Exception as e:
20         print(e)
21     finally:
22         conn.close()
23 if __name__ == "__main__":
24     server(8001)
gevent_server
 1 import socket
 2 HOST = "localhost"
 3 PORT = 8001
 4 s = socket.socket()
 5 s.connect((HOST,PORT))
 6 while True:
 7     msg = bytes(input(">>:"),encoding="utf-8")
 8     s.sendall(msg)
 9     data = s.recv(1024)
10     print("Received:",data)
11 s.close()
gevent_client

 

转载于:https://www.cnblogs.com/alpari-wang/p/9909316.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值