队列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. 所有的GUI Toolkit,类型之多真开眼界

    The GUI Toolkit, Framework Page User interfaces occupy an important part of software development. Th ...

  2. android数据库持久化框架

    android数据库持久化框架

  3. HDU 3507 Print Article(CDQ分治+分治DP)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3507 [题目大意] 将长度为n的数列分段,最小化每段和的平方和. [题解] 根据题目很容易得到dp ...

  4. openstack windows 2008 img

    1,制作镜像主机pre Env yum -y install qemu-img virt-install libvirt 2,配置bridge

  5. java常用日期函数总结

    请记得要引入java.util.Date和java.text.SimpleDateFormat两个包 1.计算某一月份的最大天数 Calendar time=Calendar.getInstance( ...

  6. Oracle 生成指定范围内随机日期

    Oracle生成一个指定范围内的随机日期 /* 年1月1日)的整数偏移量来保存(即把日期保存为一个数字); * 因此可通过寻找‘指定日期’与‘关键日期’相对应的整数偏移量,再加一个指定范围内的随机整数 ...

  7. HDU1506 ( Largest Rectangle in a Histogram ) [dp]

    近期情绪太不稳定了.可能是由于在找实习这个过程碰壁了吧.第一次面试就跪了,可能是我面的是一个新公司,制度不完好,我感觉整个面试过程全然不沾编程,我面试的还是软件开发-后来我同学面试的时候.说是有一道数 ...

  8. Java中Iterator(迭代器)的用法及其背后机制的探究

    在Java中遍历List时会用到Java提供的Iterator,Iterator十分好用,原因是: 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结 ...

  9. 五毛的cocos2d-x学习笔记06-处理用户交互

    前几篇感觉自己在写教育文章,╮(╯▽╰)╭.今天换成开发者的口吻,毕竟我也是在边学边写博客. 处理用户交互包括:单点触摸.多点触摸.事件传递.传感器.物理按键等部分. 单点触摸: 触摸事件传递顺序 o ...

  10. mapreduce 关于小文件导致任务缓慢的问题

    小文件导致任务执行缓慢的原因: 1.很容易想到的是map task 任务启动太多,而每个文件的实际输入量很小,所以导致了任务缓慢 这个可以通过 CombineTextInputFormat,解决,主要 ...