队列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的更多相关文章

  1. Python学习路程day9

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...

  2. 【坚持】Selenium+Python学习记录 DAY9

    2018/05/29 [来源:菜鸟教程](http://www.runoob.com/python3/python3-examples.html) 运算符重载 https://segmentfault ...

  3. Python学习笔记 - day9 - 模块与包

    模块与包 一个模块就是一个包含了Python定义和声明的文件,文件名就是模块名加上.py的后缀,导入一个py文件,解释器解释该py文件,导入一个包,解释器解释该包下的 __init__.py 文件,所 ...

  4. 【目录】Python学习笔记

    目录:Python学习笔记 目标:坚持每天学习,每周一篇博文 1. Python学习笔记 - day1 - 概述及安装 2.Python学习笔记 - day2 - PyCharm的基本使用 3.Pyt ...

  5. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  6. Python学习--01入门

    Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...

  7. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  8. Python学习路径及练手项目合集

    Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159

  9. python学习笔记-python程序运行

    小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...

随机推荐

  1. Java 程序中的多线程

    概述 synchronized  关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C. D等)正在用这个方法,有的话要等正在使用synch ...

  2. uva 10404 Bachet's Game(完全背包)

    题目连接:10404 - Bachet's Game 题目大意:由一堆石子, 给出石子的总数, 接下来由stan和ollie两个人玩游戏,给出n, 在给出n种取石子的方法(即为每次可取走石子的数量), ...

  3. 生产环境提升rman备份速度----启动块跟踪

    生产环境提升rman备份速度----启动块跟踪 [环境] AIX(5300-08).oracle10g(10.2.0.1.0-64bit) [目标] 因为生产环境数据量较大,欲加快rman备份的速度 ...

  4. 对Devexpress ASP.NET组件的一些看法

    使用.net开发的应该都熟悉DevExpress这套组件,强大的功能,显著提高开发效率和提升用户体验. 不过好像大都用winform, 说起用asp.net组件来开发webform,很多人开口就说慢, ...

  5. MVC4入门指南

    本系列共10篇文章,翻译自Asp.Net MVC4 官方教程,由于本系列文章言简意赅,篇幅适中,从一个示例开始讲解,全文最终完成了一个管理影片的小系统,非常适合新手入门Asp.Net MVC4,并由此 ...

  6. 跳出for循环

    如下面,有两个循环,break只能退出一个for循环,不能直接跳过第二个for循环 for (Type type : types) { for (Type t : types2) { if (some ...

  7. Android应用开发基础篇(7)-----BroadcastReceiver

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/22/2363644.html 一.概述 BroadcastReceiver,意思就是广播信息接收 ...

  8. SqlHelp

    using System.Configuration;using System.Data; public class SqlHelp { private static string connectio ...

  9. servlet三种实现方式之二继承GenericServlet开发

    servlet有三种实现方式: 1.实现servlet接口 2.继承GenericServlet 3.通过继承HttpServlet开发servlet 第二种示例代码如下(已去掉包名): //这是第二 ...

  10. SAE上使用本地sql文件建表时出错解决方法

    在SAE上部署网站时需要上传本地的数据库结构,我也导出了本地数据库为sql文件,但是上传到SAE上时遇到了如下错误: MySQL 返回: #1044 - Access denied for user ...