循序渐进Python3(八) -- 1 -- socket进阶

news/2024/7/9 16:39:21 标签: epoll, python, 操作系统

IO多路复用

I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。


Linux中的 select,poll,epoll 都是IO多路复用的机制。

python plain">select
 
python plain">select最早于 python value">1983 python plain">年出现在 python value">4.2BSD python plain">中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。
python plain">select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。
python plain">select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为 python value">1024 python plain">,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
python plain">另 外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量 TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。
 
python plain">poll
 
python plain">poll在 python value">1986 python plain">年诞生于System V Release python value">3 python plain">,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
python plain">poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
python plain">另 外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将 再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。
 
python plain">epoll
 
python plain">直到Linux2. python value">6 python plain">才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2. python value">6 python plain">下性能最好的多路I python keyword">/ python plain">O就绪通知方法。
python plain">epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
python plain">epoll 同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的 值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在 系统调用时复制的开销。
python plain">另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select python keyword">/ python plain">poll 中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某 个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。


Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。

python">
1
2
3
4
5
6
python plain">Windows Python:
python spaces">     python plain">提供: select
python plain">Mac Python:
python spaces">     python plain">提供: select
python plain">Linux Python:
python spaces">     python plain">提供: select、poll、epoll
python plain">注意:网络操作、文件操作、终端操作等均属于IO操作,对于windows只支持Socket操作,其他系统支持其他IO操作,但是无法检测 普通文件操作 自动上次读取是否已经变化。
python plain">

select方法:
句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间)
 
参数: 可接受四个参数(前三个必须)
返回值:三个列表
 
select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中
2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中
3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中
4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
   当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。

例子:
服务端:

  
客户端:
#!/usr/bin/env python
# Version = 3.5.2
# __auth__ = '无名小妖'
import socket

client = socket.socket()
client.connect(('127.0.0.1',9992))

data = client.recv(1024)
print(data.decode())
while True:
inp = input('>>>')
client.sendall(bytes(inp, encoding='utf8'))
print(client.recv(1024).decode())
client.close()
python plain"> 
python plain">
python plain">完整例子:
python plain">服务端:
python plain">
python plain">#!/usr/bin/env python
# Version = 3.5.2
# __auth__ = '无名小妖'
import socket, select

sk = socket.socket()
sk.bind(('127.0.0.1',9992))
sk.listen(5)

inputs = [sk, ]
outputs = []
while True:
# 监听sk对象,如果sk发生变化,表示有客户端来连接了,此时rlist的值为sk
rlist,wlist,e = select.select(inputs, outputs, [], 1)
# 监听conn对象,如果conn变化,表示客户端来发消息了,此时的rlist值为 客户端
print(len(inputs), len(rlist), len(outputs), len(wlist))
for r in rlist:
if r == sk: # 新连接
conn, addr = r.accept()
inputs.append(conn)
conn.sendall(bytes('hello !', encoding='utf8'))
else: # 有人发消息
print('=============')
try:
ret = r.recv(1024)
if not ret:
raise Exception('断开连接!')
else:
outputs.append(r)
except Exception as e:
inputs.remove(r)
for w in wlist:
w.sendall(bytes('respons ',encoding='utf8'))
outputs.remove(w)
python plain">
python plain">客户端:
python plain">
python plain">
python plain">#!/usr/bin/env python
# Version = 3.5.2
# __auth__ = '无名小妖'
import socket

client = socket.socket()
client.connect(('127.0.0.1',9992))

data = client.recv(1024)
print(data.decode())
while True:
inp = input('>>>')
client.sendall(bytes(inp, encoding='utf8'))
print(client.recv(1024).decode())
client.close()
python plain">
python plain">-----------------------------------------------------------------------------------------
python plain">

python plain">多线程 多进程

python plain">
python plain">一个应用程序,可以有多个进程、多个线程,默认是单进程单线程。
python plain">
python plain">python中由于有GIL(全局解释器锁)的存在,所以每次只能使用某个进程中的一个线程。
python plain">
python plain">但是上述规则只限于使用cpu的时候,如果不实用cpu,那么可以使用多线程。
python plain">
python plain">因此,在python中想提高并发有如下做法:
python plain">
python plain">  io密集型:可以使用多线程(因为io操作不实用cpu)
python plain">
python plain">  计算密集型:使用多进程
python plain">
python plain">
python plain">
python plain">列子:
python plain">
python plain">
python plain">import time
def f1(arg, t=None):
if t:
t._delete()
time.sleep(5)
print(arg)


# for i in range(10):
# f1(i)
# 单进程、单线程的应用程序
import threading
t1 = threading.Thread(target=f1, args=(1,))
# t1.setDaemon(True) # true,表示主线程不等此子线程
t1.start()# 不代表当前线程会被立即执行
#t.join(2) # 表示主线程到此,等待 ... 直到子线程执行完毕
# 参数,表示主线程在此最多等待n

t2 = threading.Thread(target=f1, args=(2,t1))
t2.start()# 不代表当前线程会被立即执行
print('end')
print('end')
print('end')
print('end')
print('end')
python plain">

python plain">创建线程的两种方式:

python plain">
python plain">第一种:(常用的)
python plain">
python plain">import threading
def f1(arg):
print(arg)

t = threading.Thread(target=f1, args=(123,))
t.start()
t.run()
run
python plain">
python plain">
python plain">
python plain">第二种:
python plain">
python plain">import threading
class MyThread(threading.Thread):
def __init__(self, func,args):
self.func = func
self.args = args
super(MyThread, self).__init__()

def run(self):
self.func(self.args)

def f2(arg):
print(arg)

obj = MyThread(f2,123)
obj.start()
python plain">
python plain">
python plain">
python plain">----------------------------------------------------------------------------------
python plain">

python plain">队列

python plain">
python plain">python队列是创建在内存的,当程序退出,队列同时清空。
python plain">
python plain">
python plain">import queue
# queue.Queue,先进先出队列
# queue.LifoQueue,后进先出队列
# queue.PriorityQueue,优先级队列
# queue.deque,双向对队
python plain">

python plain">先进先出队列

python plain">
python plain">
python plain">#!/usr/bin/env python
# Version = 3.5.2
# __auth__ = '无名小妖'
import queue

q = queue.Queue(2) # 队列最大长度
q.put(11) # put 放数据
q.put(22)
print(q.qsize()) # 查看队列当前元素个数
q.put(33, timeout=2) # timeout 等待时间,2
q.put(33, block=False) # block 是否阻塞,False表示不阻塞

print(q.get()) # get 取数据,默认阻塞
print(q.empty()) # 检查队列是否为空,返回TrueFalse
# maxsize 最大支持的个数

# join,task_done,阻塞进程,当队列中任务执行完毕之后,不再阻塞
import queue
q = queue.Queue()
q.put(123)
q.put(123)
q.get()
q.task_done() # 告诉队列取完了
q.get()
q.task_done()
q.join() # 结束
python plain">
python plain">
python plain">
python plain">
python plain">----------------------------------------------------------------------------------
python plain">

python plain">生产者消费者模型

python plain">
python plain">产生原因:提高应对并发的能力
python plain">
python plain">
python plain">

python plain">线程

python plain">
python plain">
python plain">
python plain">
python plain">
python plain">
python plain">import threading
python plain">
python plain">import time
python plain">
python plain">  
python plain">
python plain">def show(arg):
python plain">
python plain">    time.sleep(1)
python plain">
python plain">    print('thread'+str(arg))
python plain">
python plain">
python plain">
python plain">for i in range(10):
python plain">
python plain">    t = threading.Thread(target=show, args=(i,))
python plain">
python plain">    t.start()
python plain">
python plain">
python plain">
python plain">print('main thread stop')
python plain">
python plain">
python plain">
python plain">上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

更多方法:

start            线程准备就绪,等待CPU调度
setName      为线程设置名称
getName      获取线程名称
setDaemon   设置为后台线程或前台线程(默认)
                   如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                    如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
join              逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
run              线程被cpu调度后自动执行线程对象的run方法
python plain">

python plain">自定义线程类

python plain">
python plain">import threading import time class MyThread(threading.Thread): def __init__(self,num): threading.Thread.__init__(self) self.num = num def run(self):#定义每个线程要运行的函数 print("running on number:%s" %self.num) time.sleep(3) if __name__ == '__main__': t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start()
python plain">
python plain">
python plain">

python plain">线程锁:

python plain">
python plain">由于线程之间是进行随机调度,并且每个线程可能只执行n条,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻只允许一个线程操作。
python plain">
python plain">上面线程的第一个列子就未使用锁。
python plain">
python plain">import threading import time NUM = 10 def func(i,l): global NUM # 上锁 l.acquire() # 30,5 25m5,20 NUM -= 1 time.sleep(2) print(NUM,i) # 开锁 l.release() # lock = threading.Lock() # lock = threading.RLock() # 支持多层锁 lock = threading.BoundedSemaphore(5) for i in range(30): t = threading.Thread(target=func,args=(i,lock,)) t.start()
python plain">
python plain">

python plain">

python plain">

python plain">信号量(Semaphore)

python plain">

python plain">互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

python plain">

python plain">

python plain">

python plain">import threading,time

python plain">

python plain"> 

python plain">

python plain">def run(n):

python plain">

python plain">    semaphore.acquire()

python plain">

python plain">    time.sleep(1)

python plain">

python plain">    print("run the thread: %s" %n)

python plain">

python plain">    semaphore.release()

python plain">

python plain"> 

python plain">

python plain">if __name__ == '__main__':

python plain">

python plain">

python plain">

python plain">    num= 0

python plain">

python plain">    semaphore  = threading.BoundedSemaphore(5) #最多允许5个线程同时运行

python plain">

python plain">    for i in range(20):

python plain">

python plain">        t = threading.Thread(target=run,args=(i,))

python plain">

python plain">        t.start()

python plain">

python plain">

python plain">

python plain">事件(event)

python plain">

python plain"> python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。 事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。 clear:将“Flag”设置为False set:将“Flag”设置为True

python plain">
python plain">列子:
import threading 
python plain">
python plain">def func(i,e): 
python plain">
python plain">    print(i) e.wait() # 检测是什么等,如果是红灯,停;绿灯,行 
python plain">
python plain">    print(i+100) event = threading.Event() 
python plain">
python plain">    for i in range(10): 
python plain">
python plain">        t = threading.Thread(target=func, args=(i,event,)) 
python plain">
python plain">        t.start() 
python plain">
python plain">#======== 
python plain">
python plain">event.clear() # 设置成红灯 
python plain">
python plain">inp = input('>>>') 
python plain">
python plain">if inp == "1": 
python plain">
python plain">    event.set() # 设置成绿灯
python plain">

python plain">

python plain">

python plain">

python plain">

python plain">条件(Condition)

python plain">

python plain">使得线程等待,只有满足某条件时,才释放n个线程

python plain">

python plain">

python plain">

python plain">例子一:

python plain">

python plain">import threading

python plain">

python plain">def func(i,con):

python plain">

python plain">    print(i)

python plain">

python plain">    con.acquire()

python plain">

python plain">    con.wait()

python plain">

python plain">    print(i+100)

python plain">

python plain">    con.release()

python plain">

python plain">

python plain">

python plain">c = threading.Condition()

python plain">

python plain">for i in range(10):

python plain">

python plain">    t = threading.Thread(target=func, args=(i,c,))

python plain">

python plain">    t.start()

python plain">

python plain">

python plain">

python plain">while True:

python plain">

python plain">    inp = input('>>>')

python plain">

python plain">    if inp == 'q':

python plain">

python plain">        break

python plain">

python plain">    #  以下 为 条件 代码,inp为几 上面线程就会执行几个

python plain">

python plain">    c.acquire()

python plain">

python plain">    c.notify(int(inp))

python plain">

python plain">    c.release()

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">例子二:

python plain">

python plain">

python plain">
python plain">import threading # 输入true则执行一个线程 def condition(): ret = False r = input('>>>') if r == 'true': ret = True else: ret = False return ret def func(i,con): print(i) con.acquire() con.wait_for(condition) print(i+100) con.release() c = threading.Condition() for i in range(10): t = threading.Thread(target=func, args=(i,c,)) t.start()
python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">定时器(Timer)

python plain">

python plain">定时器,指定n秒后执行某操作

python plain">

python plain">

python plain">

python plain">from threading import Timer

python plain">

python plain">

python plain">

python plain">def hello():

python plain">

python plain">    print("hello, world")

python plain">

python plain">

python plain">

python plain">t = Timer(1, hello)

python plain">

python plain">t.start()  # after 1 seconds, "hello, world" will be printed

python plain">

python plain">

python plain">

python plain">线程池

python plain">

python plain">什么是线程池? 

python plain">

python plain">诸如web服务器、数据库服务器、文件服务器和邮件服务器等许多服务器应用都面向处理来自某些远程来源的大量短小的任务。 构建服务器应用程序的一个过于简单的模型是:每当一个请求到达就创建一个新的服务对象,然后在新的服务对象中为请求服务。 但当有大量请求并发访问时,服务器不断的创建和销毁对象的开销很大。 所以提高服务器效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这样就引入了“池”的概念, “池”的概念使得人们可以定制一定量的资源,然后对这些资源进行复用,而不是频繁的创建和销毁。

python plain">

python plain"> 线程池是预先创建线程的一种技术。 这些线程都是处于睡眠状态,即均为启动,不消耗CPU,而只是占用较小的内存空间。 当请求到来之后,缓冲池给这次请求分配一个空闲线程,把请求传入此线程中运行,进行处理。 当预先创建的线程都处于运行状态,即预制线程不够,线程池可以自由创建一定数量的新线程,用于处理更多的请求。 当系统比较闲的时候,也可以通过移除一部分一直处于停用状态的线程。

python plain">

python plain"> 线程池的注意事项 

python plain">

python plain">虽然线程池是构建多线程应用程序的强大机制,但使用它并不是没有风险的。在使用线程池时需注意线程池大小与性能的关系,注意并发风险、死锁、资源不足和线程泄漏等问题。

python plain">

python plain"> 1、线程池大小。多线程应用并非线程越多越好,需要根据系统运行的软硬件环境以及应用本身的特点决定线程池的大小。 一般来说,如果代码结构合理的话,线程数目与CPU 数量相适合即可。 如果线程运行时可能出现阻塞现象,可相应增加池的大小;如有必要可采用自适应算法来动态调整线程池的大小,以提高CPU 的有效利用率和系统的整体性能。 

python plain">

python plain">2、并发错误。多线程应用要特别注意并发错误,要从逻辑上保证程序的正确性,注意避免死锁现象的发生。

python plain">

python plain"> 3、线程泄漏。这是线程池应用中一个严重的问题,当任务执行完毕而线程没能返回池中就会发生线程泄漏现象。 

python plain">

python plain">线程池要点: 

python plain">

python plain"> 1、通过判断等待的任务数量和线程池中的最大值,取最小值来判断开启多少线程来工作 比如: 任务数是3,进程池最大20 ,那么咱们只需要开启3个线程就行了。 任务数是500,进程池是20,那么咱们只开20个线程就可以了。 取最小值 

python plain">

python plain"> 2、实现线程池正在运行,有一个查看的功能,查看一下现在线程里面活跃的线程是多少等待的是多少? 线程总共是多少,等待中多少,正在运行中多少 作用: 方便查看当前线程池状态 能获取到这个之后就可以当线程一直处于空闲状态 查看状态用:上下文管理来做,非常nice的一点

python plain">

python plain"> 3、关闭线程

python plain">

python plain">

python plain">

python plain">简单线程池的实现:

python plain">

python plain">

python plain">
python plain">import queue import threading import time class ThreadPool: def __init__(self, maxsize=5): self.maxsize = maxsize self._q = queue.Queue(maxsize) for i in range(maxsize): self._q.put(threading.Thread)
python plain">
python plain"> def get_thread(self): return self._q.get() def add_thread(self): self._q.put(threading.Thread) pool = ThreadPool(5) def task(arg,p): print(arg) time.sleep(1) p.add_thread() for i in range(100): # threading.Thread类 t = pool.get_thread() obj = t(target=task,args=(i,pool,)) obj.start()
python plain">
python plain">
python plain">
python plain">--------------------------------------------------------------------------------------------
python plain">
python plain">

python plain">Python 进程

python plain">

python plain">注意:由于进程之间的数据需要各自持有一份,所以创建进程需要非常大的开销。

python plain">

python plain">      进程各自持有一份数据,默认无法共享数据。

python plain">

python plain">

python plain">

python plain">进程使用:

python plain">

python plain">from multiprocessing import Process from multiprocessing import queues import multiprocessing from multiprocessing import Array def foo(i,arg): # arg.put(i) # print('say hi',i,arg.qsize()) arg[i] = i + 100 for item in arg: print(item) print('================') if __name__ == "__main__": # li = [] # li = queues.Queue(20,ctx=multiprocessing) li = Array('i', 10) for i in range(10): p = Process(target=foo,args=(i,li,)) #p.daemon = True p.start() #p.join()

python plain">

python plain">

python plain">

python plain">实现数据共享的方式:

python plain">

python plain">queues,array,Manager.dict

python plain">

python plain">

python plain">
python plain">数据共享:(queues)
python plain">
python plain">from multiprocessing import Process
from multiprocessing import queues
import multiprocessing
def foo(i,arg):
arg.put(i)
print('say hi',i,arg.qsize())

if __name__ == "__main__":
# li = []
li = queues.Queue(20,ctx=multiprocessing) # 实现数据共享queues 和 multiprocessing
for i in range(10):
p = Process(target=foo,args=(i,li,))
#p.daemon = True
p.start()
#p.join()
python plain">
python plain">
python plain">
python plain">数据共享:(array)
python plain">
python plain">
python plain">from multiprocessing import Process
from multiprocessing import Array # 数组,类似列表

def foo(i,arg):
arg[i] = i + 100
for item in arg:
print(item)
print('================')
if __name__ == "__main__":
li = Array('i', 10)
for i in range(10):
p = Process(target=foo,args=(i,li,))
p.start()
python plain">
python plain">数据共享:(Manager
python plain">
python plain">
python plain">
python plain">from multiprocessing import Process
from multiprocessing import Manager

def foo(i,arg):
arg[i] = i + 100
print(arg.values())
if __name__ == "__main__":
obj = Manager()
li = obj.dict()
for i in range(10):
p = Process(target=foo,args=(i,li,))
p.start()
p.join() # 方式二
# 方式一
# import time
# time.sleep(0.1)
python plain">
python plain">
python plain">
python plain">

python plain">进程锁:

python plain">
python plain">没锁:
python plain">
python plain">
python plain">from multiprocessing import Process
from multiprocessing import Array
import time

def foo(i,lis):
lis[0] = lis[0] - 1
time.sleep(1)
print('say hi',lis[0])
if __name__ == "__main__":
li = Array('i', 1)
li[0] = 10
for i in range(10):
p = Process(target=foo,args=(i,li))
p.start()
python plain">
python plain">
python plain">有锁:
python plain">
python plain">
python plain">from multiprocessing import Process
from multiprocessing import Array
from multiprocessing import RLock
import time
def foo(i,lis,lc):
lc.acquire()
lis[0] = lis[0] - 1
time.sleep(1)
print('say hi',lis[0])
lc.release()
if __name__ == "__main__":
# li = []
li = Array('i', 1)
li[0] = 10
lock = RLock()
for i in range(10):
p = Process(target=foo,args=(i,li,lock))
p.start()
python plain">
python plain">

python plain">进程池:

python plain">

python plain">

python plain">

python plain">进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

python plain">

python plain">进程池中有两个方法:

python plain">

python plain">apply

python plain">apply_async python plain">

python plain">

python plain">
python plain">例子:
from multiprocessing import Pool
import time
def f1(arg):
print(arg,'b')
time.sleep(5)
print(arg,'a')
if __name__ == "__main__":
pool = Pool(5)
for i in range(30):
# pool.apply(func=f1,args=(i,))
pool.apply_async(func=f1,args=(i,))
# pool.close() # 所有的任务执行完毕
time.sleep(1)
pool.terminate() # 立即终止,当前已经执行的任务完毕
pool.join() # 夯住,前面必须执行close或者terminate方法
pass
python plain">
python plain">-----------------------------------------------------------------------------------------------------------------
python plain">
python plain">
python plain">
python plain">
python plain">

python plain">协程:

python plain">

python plain">线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

python plain">

python plain">协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

python plain">

python plain">协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

python plain">

python plain">先看一下基本用法:
greenlet:

python plain">

python plain">

python plain">from greenlet import greenlet

def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()

def test2():
print(56)
gr1.switch()
print(78)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
python plain">

python plain">gevent:

python plain">

python plain">

python plain">import gevent
def foo():
print('Running in foo')
gevent.sleep(0)
print('Explicit context switch to foo again')
def bar():
print('Explicit context to bar')
gevent.sleep(0)
print('Implicit context switch back to bar')
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])
python plain">
python plain">
python plain">
python plain">简单的例子:
python plain">
python plain">
python plain">from gevent import monkey; monkey.patch_all()
import gevent
import requests
def f(url):
print('GET: %s' % url)
resp = requests.get(url)
data = resp.text
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])
python plain">
python plain">
python plain">
python plain">返回结果:
python plain">
python plain">GET: https://www.python.org/ GET: https://www.yahoo.com/ GET: https://github.com/ 47433 bytes received from https://www.python.org/. 25751 bytes received from https://github.com/. 462131 bytes received from https://www.yahoo.com/.
python plain">
python plain">
python plain">
python plain">
python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">

python plain">



来自为知笔记(Wiz)


转载于:https://www.cnblogs.com/wumingxiaoyao/p/5942842.html


http://www.niftyadmin.cn/n/1177192.html

相关文章

ubuntu中mysql怎么退出命令_怎样在 Ubuntu Linux 上安装 MySQL

本教程教你如何在基于 Ubuntu 的 Linux 发行版上安装 MySQL。对于首次使用的用户,你将会学习到如何验证你的安装和第一次怎样去连接 MySQL。MySQL 是一个典型的数据库管理系统。它被用于许多技术栈中,包括流行的 LAMP (Linux、Apache、MySQL、…

https大势已来?看腾讯专家如何在高并发压测中支持https

WeTest 导读 用epoll编写一个高并发网络程序是很常见的任务,但在epoll中加入ssl层的支持则是一个不常见的场景。腾讯WeTest服务器压力测产品,在用户反馈中收到了不少支持https协议的请求。基于此,本文介绍了在基于epoll的高并发机器人框架中加…

JMeter3.0_插件管理

JMeter Plugins 一直以来,JMeter Plugins为我们提供了很多高价值的JMeter插件,比如: 用于服务器性能监视的PerfMon Metrics Collector用于建立压力变化模型的Stepping Thread Group用于Json解析的JSON Path Extractor用于展示响应时间曲线的Response Tim…

tp5不启用伪静态_网站建设要懂得分清伪静态和纯静态的使用差异化

懂得建设网站的专业人士都知道,对于伪静态和纯静态两者之前是有区别的,在使用过程中也会存在一定的差异化。具体情况跟着小编一起去看看吧。(1)伪静态页面伪静态网页从表面看其实和纯静态页面是一样的,都是,html或者,h…

mysql var目录很快_在Docker中体验 MySQL 主从分离以及数据库中间件 MyCat Part 1

一、在本机上安装并设置 Docker首先到 Docker 官网 (https://docs.docker.com/) 下载并安装对应你操作系统的最新 Docker 桌面版。我的操作系统是 macOS,对应的版本是 Docker Desktop for Mac。Windows 用户请确保你的操作系统是 Windows 10 64 位专业版。如果你的 …

JQueryMobile开发必须的知道的知识

移动Web页面的基本组成元素&#xff1a; 页面头部&#xff0c;页面内容&#xff0c;页面底部 <!DOCTYPE html> <html> <head> <title>My Page</title> <meta name"viewport" content"widthdevice-width, initial-scale1"…

Web程序员开发App系列 - 开发我的第一个App,源码下载

Web程序员开发App系列 Web程序员开发App系列 - 认识HBuilderWeb程序员开发App系列 - 申请苹果开发者账号Web程序员开发App系列 - 调试Android和iOS手机代码Web程序员开发App系列 - 开发我的第一个App待续目录 前言源码和App下载准备工作查看留言页面增加留言页面前言 看了前面几…

百度地图调用

1、引入外部文件 <script src"http://api.map.baidu.com/api?v1.1&amp;servicestrue" type"text/javascript"></script> <script src"http://api.map.baidu.com/getscript?v1.1&amp;ak&amp;servicestrue&amp;t20130…