python学习之day9
队列queue
队列是线程安全的,它保证多线程间的数据交互的一致性。
先进先出队列Queue
import queue
q = queue.Queue(maxsize=3) #maxsize为队列最大长度,不设置则为无限长
q.put(1) #往队列放数据
q.put(2,timeout=1) #设置超时时间,超过时间抛异常
q.put_nowait(4) #如果队列已满,直接抛异常
print(q.qsize()) #获取队列长度
print(q.get()) # 从队列中获取数据,如果没有会一直等待
print(q.get(timeout=1)) # 设置超时时间,超过时间会抛异常
print(q.get_nowait()) # 如果没有数据直接抛异常
执行结果:
3
1
2
4
后进先出队列LifoQueue
import queue
q = queue.LifoQueue(maxsize=3) #maxsize为队列最大长度,不设置则为无限长
q.put(1) #往队列放数据
q.put(2,timeout=1) #设置超时时间,超过时间抛异常
q.put_nowait(4) #如果队列已满,直接抛异常
print(q.qsize()) #获取队列长度
print(q.get()) # 从队列中获取数据,如果没有会一直等待
print(q.get(timeout=1)) # 设置超时时间,超过时间会抛异常
print(q.get_nowait()) # 如果没有数据直接抛异常
执行结果:
3
4
2
1
设定优先级PriorityQueue
import queue
q = queue.PriorityQueue(maxsize=3)
q.put((10,[1,2,3])) # 优先级和数据必须以元组的形式存在
q.put((2,555))
q.put_nowait((5,"abc"))
print(q.qsize())
print(q.get())
print(q.get(timeout=1))
print(q.get_nowait())
执行结果:
3
(2, 555)
(5, 'abc')
(10, [1, 2, 3])
生产者消费者模型:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 生产者生产包子,消费者吃包子,服务员(队列)传递包子 import queue,time
import threading
q = queue.Queue(maxsize=3) #设定队列(服务员)最大长度(队列中最多3个包子)
def producer(name):
baozi = 0
while True:
time.sleep(1)
# if q.qsize() < 3:
q.put(baozi)
print("\033[32;1mproducer {} produce a baozi {}\033[0m".format(name,baozi))
baozi += 1
q.join() #join方法等待队列为空告诉生产者继续生产 def consumer(name):
while True:
if q.qsize() > 0:
bz = q.get()
print("\033[35;1mconsumer {} eat a baozi {}\033[0m".format(name,bz))
time.sleep(1)
q.task_done() #每次吃完包子告诉队列(服务员) if __name__ == "__main__":
c1 = threading.Thread(target=consumer,args=("A",),)
c2 = threading.Thread(target=consumer,args=("B",),)
c3 = threading.Thread(target=consumer,args=("C",),)
p1 = threading.Thread(target=producer,args=("akon",),)
p2 = threading.Thread(target=producer,args=("alex",),)
p3 = threading.Thread(target=producer,args=("cloris",),)
c1.start()
c2.start()
c3.start()
p1.start()
p2.start()
p3.start()
执行结果:
producer akon produce a baozi 0
consumer B eat a baozi 0
producer cloris produce a baozi 0
producer alex produce a baozi 0
consumer C eat a baozi 0
consumer A eat a baozi 0
producer alex produce a baozi 1
consumer A eat a baozi 1
producer cloris produce a baozi 1
producer akon produce a baozi 1
consumer B eat a baozi 1
consumer C eat a baozi 1
......
协程
协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是协程:协程是一种用户态的轻量级线程。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:
协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
协程在切换的时候都是在一个线程间进行切换,协程本身就是一个单线程
协程的好处:
- 无需线程上下文切换的开销
- 无需原子操作锁定及同步的开销
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
缺点:
- 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
- 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
IO操作都是操作系统级别的
Gevent
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
一个简单的模拟异步IO操作:
#!/usr/bin/env python
# -*- coding:utf-8 -*- import gevent def foo():
print("\033[31;1mruning in foo\033[0m")
gevent.sleep(1)
print("\033[31;1mruning switch back\033[0m") def second():
print("\033[32;1mruning in second\033[0m")
gevent.sleep(1)
print("\033[32;1msecond switch back\033[0m") def third():
print("\033[33;1mruning in third\033[0m")
gevent.sleep(1)
print("\033[33;1mthird switch back\033[0m") gevent.joinall([
gevent.spawn(foo),
gevent.spawn(second),
gevent.spawn(third)
])
执行结果:
runing in foo
runing in second
runing in third
runing switch back
third switch back
second switch back
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import gevent def task(pid):
"""
Some non-deterministic task
"""
gevent.sleep(0.5)
print('Task %s done' % pid) def synchronous():
for i in range(10):
task(i) def asynchronous():
threads = [gevent.spawn(task, i) for i in range(10)]
gevent.joinall(threads) print('Synchronous:')
synchronous() print('Asynchronous:')
asynchronous()
同步与异步的性能区别
from gevent import monkey; monkey.patch_all()
import gevent
from urllib.request import urlopen def f(url):
print('GET: %s' % url)
resp = urlopen(url)
data = resp.read()
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/'),
])
遇到IO阻塞会自动切换任务
执行结果:
GET: https://www.python.org/
GET: https://www.yahoo.com/
GET: https://github.com/
24132 bytes received from https://github.com/.
46958 bytes received from https://www.python.org/.
458329 bytes received from https://www.yahoo.com/.
通过gevent实现单线程下多socket并发
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import gevent
from gevent import socket,monkey
monkey.patch_all()
def server(port):
s = socket.socket()
s.bind(("",port))
s.listen(500)
while True:
cli,addr = s.accept()
gevent.spawn(handle_request,cli) def handle_request(s):
try:
while True:
data = s.recv(1024)
print("recv:",data.decode("utf-8"))
s.send(data)
if not data:
s.shutdown(socket.SHUT_WR)
except Exception as ex:
print(ex)
finally:
s.close()
if __name__ == "__main__":
server(8888)
server
#!/usr/bin/env python
# -*- coding:utf-8 -*- import socket host = "127.0.0.1"
port = 8888
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))
while True:
msg = input(">>:").strip()
if len(msg) == 0:continue
if msg == "q":break
msg = bytes(msg,encoding="utf-8")
s.sendall(msg)
data = s.recv(1024)
print("received:",data.decode("utf-8"))
s.close()
client
select
Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, and pipes(所有带fileno()方法的文件句柄)何时变成readable 和writeable, 或者通信错误,select()使得同时监控多个连接变的简单,并且这比写一个长循环来等待和监控多客户端连接要高效,因为select直接通过操作系统提供的C的网络接口进行操作,而不是通过Python的解释器。
#!/usr/bin/env python
# -*- coding:utf-8 -*- import select,socket,sys,queue server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket通信实例
server.setblocking(False) #设置socket不阻塞 server_address = ("localhost",9999) # 声明IP和端口号
print(sys.stderr,"starting up on %s port %s"%server_address)
server.bind(server_address) #绑定IP和端口
server.listen(5) #最大链接数5个 inputs = [server] #定义一个列表inputs并把server实例作为第一个元素,如果客户端连接请求过来,就把这个客户端连接存到这个列表
outputs = [] #定义一个空列表,如果服务器端需要发送数据给客户端,就把客户端连接存到这个列表
message_queues = {} #定义一个空字典,用来存储要发送给客户端的数据,键(key)是客户端连接,值(value)是数据 while inputs: #server作为第一个元素保证了程序可以往下走,并一直循环
print("\nwaiting for the next event")
readable,writable,exceptional = select.select(inputs,outputs,inputs) #select阻塞等待IO变化,三个通信列表分别监控所有外部发送过来的数据、所有要发出去的数据和错误信息
for s in readable: #循环readable,相当于循环inputs列表
if s is server: #如果s是server就会用accept方法接收新的连接
connection,client_address = s.accept()
print("new connection from",client_address)
connection.setblocking(False)
inputs.append(connection) #新的连接进来就把它放进inputs列表里
message_queues[connection] = queue.Queue() #生成一个以连接为键,以队列为值的元素放进字典message_queues里
else: #如果s不是server,就开始接受数据
data = s.recv(1024)
if data:
print(sys.stderr,"received '%s' from %s "%(data,s.getpeername()))
message_queues[s].put(data) #如果收到数据,就把数据先存起来
if s not in outputs: #如果outputs里面还没有这个连接,就把连接加入outputs中
outputs.append(s)
else: #如果没收到数据,说明连接已经断开,以下是把这个连接的所有数据删除
print("closing",client_address,"after read no data")
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
message_queues.pop(s)
for s in writable: #writable对应了outputs,这里循环把需要发出去的数据发送
try:
next_msg = message_queues[s].get_nowait().decode("gbk") #获取数据
except queue.Empty: #如果队列为空说明没有数据
print("output queue for",s.getpeername(),"is empty")
outputs.remove(s) #把连接从outputs中移除,避免下一次循环重复检测
else:
print("sending '%s' to %s"%(next_msg,s.getpeername()))
s.send(bytes(next_msg,encoding="gbk")) #发送数据给客户端
for s in exceptional: #exceptional负责把出错的连接删除
print("handling exceptional condition for",s.getpeername())
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
message_queues.pop(s)
select_server
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,sys messages = ["this is a test message",
"please don't reply",
"don't reply",] server_address = ("localhost",9999)
socks = [
socket.socket(socket.AF_INET,socket.SOCK_STREAM),
socket.socket(socket.AF_INET,socket.SOCK_STREAM),
# socket.socket(socket.AF_INET,socket.SOCK_STREAM),
# socket.socket(socket.AF_INET,socket.SOCK_STREAM)
] print(sys.stderr,"connecting to %s port %s"%server_address) for s in socks:
s.connect(server_address)
for message in messages:
for s in socks:
# print(sys.stderr,"%s:sending '%s'"%(s.getsockname(),message))
print("%s:sending '%s'"%(s.getsockname(),message))
s.send(bytes(message,encoding="gbk")) for s in socks:
data = s.recv(1024)
# print(sys.stderr,"%s: received '%s'"%(s.getsockname(),data.decode("gbk")))
print("%s: received '%s'"%(s.getsockname(),data.decode("gbk")))
if not data:
print("closing socket",s.getsockname())
s.close()
select_client
数据库mysql基础
http://www.cnblogs.com/wupeiqi/articles/5095821.html
python学习之day9的更多相关文章
- Python学习路程day9
本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...
- 【坚持】Selenium+Python学习记录 DAY9
2018/05/29 [来源:菜鸟教程](http://www.runoob.com/python3/python3-examples.html) 运算符重载 https://segmentfault ...
- Python学习笔记 - day9 - 模块与包
模块与包 一个模块就是一个包含了Python定义和声明的文件,文件名就是模块名加上.py的后缀,导入一个py文件,解释器解释该py文件,导入一个包,解释器解释该包下的 __init__.py 文件,所 ...
- 【目录】Python学习笔记
目录:Python学习笔记 目标:坚持每天学习,每周一篇博文 1. Python学习笔记 - day1 - 概述及安装 2.Python学习笔记 - day2 - PyCharm的基本使用 3.Pyt ...
- Python学习--04条件控制与循环结构
Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...
- Python学习--01入门
Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...
- Python 学习小结
python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...
- Python学习路径及练手项目合集
Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159
- python学习笔记-python程序运行
小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...
随机推荐
- Qt在windows与Mac OS中获取执行程序版本号
1 windows中获取执行文件exe的版本号 QString GetFileVertion(QString aFullName) { QString vRetVersion; string vF ...
- Codeforces 700A As Fast As Possible(二分答案)
[题目链接] http://codeforces.com/problemset/problem/700/A [题目大意] 有一辆限载k人速度为v2的车,n个步行速度均为v1的人要通过一段长度为l的距离 ...
- Windows Latex 中日文字体设置例
中文字体例: \documentclass[CJK]{article} \usepackage{CJKutf8} \newcommand{\songti}{\CJKfamily{song}} % 宋体 ...
- H5 应用程序返回button的js代码设计,设计仿stack
history.back(); 该代码具有天然的缺陷,二手知道,于H5应用,尤其是模仿移动应用程序时,,这是不够. 在放大期js为了实现类似特征,请轻喷. 不多说,上代码: /** * Created ...
- border-radius 知识点
border-radius:50px; 边框半径 CSS度量值都:em.px.百分比如果设置1个值,表示4个圆角都使用这个值.如果设置两个值,表示左上角和右下角使用第一个值,右上角和左下角使用第二个值 ...
- zoj 1962 How Many Fibs?(字符串化为数字处理)
事实证明还是,题目拿到手之后,还是还是好好动手划一下比较好,不然直接想打哪!打到哪!很容易乱掉的.将数字倒着弄成字符串比较好处理. #include<stdio.h> #include&l ...
- iOS工程上传AppStore时遇到的问题“ERROR ITMS-90046”解析
在我们将代码写完整,测试没有bug之后,我们就可以将它上传到AppStore了,上传的过程只要操作正确并不会有太大的问题,但是打包的过程中会出现一些小问题,导致打的包不能上传或者上传的时候会出现错误. ...
- Depth-First Search
深度搜索和宽度搜索对立,宽度搜索是横向搜索(队列实现),而深度搜索是纵向搜索(递归实现): 看下面这个例子: 现在需要驾车穿越一片沙漠,总的行驶路程为L.小胖的吉普装满油能行驶X距离,同时其后备箱最多 ...
- C# 中带@字符串中的转义符号
C#转义字符 c#里 @ 表示的是:1.在C#中,"c:\\temp"表示路径是c:\temp; 而@"c:\temp"就表示c:\temp; 所以,@的作用就 ...
- 2.PHP 教程_PHP 安装
您需要做什么? 找一个支持PHP和MySQL的主机 在您自己的PC机上安装web服务器,然后安装PHP和MySQL 使用支持PHP的Web的主机 如果您的服务器支持PHP,那么您不需要做任何事情. 只 ...