队列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. WM_SYSCOMMAND包括很多功能,比如:拖动左边框、拖动标题栏、滚动条滚动、点击最小化、双击标题栏——Delphi 通过事件代替了大部分常用的消息,所以Delphi 简单、易用、高效

    procedure TForm1.WMSysCommand(var Message: TWMSysCommand); var str: string; begin case Message.CmdTy ...

  2. 四种常见的提示弹出框(success,warning,error,loading)原生JavaScript和jQuery分别实现

    原文:四种常见的提示弹出框(success,warning,error,loading)原生JavaScript和jQuery分别实现 虽然说现在官方的自带插件已经有很多了,但是有时候往往不能满足我们 ...

  3. smarty如何处理状态值的显示

    比如状态,有效或者无效.这个数据库中保存的是1或者2这样的字段. 显示在列表的时候不能是1或者2吧. 以前,我都是在后台foreach,处理的.感觉处理之后,前台就不灵活了.这个值就被替换成了文字. ...

  4. hdoj Scaena Felix

    Scaena Felix Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  5. CCTableView 简单样例

    非常像android中的listview #pragma once; #include "cocos2d.h" using namespace cocos2d; //使用CCTab ...

  6. SSIS: 使用Lookup 和 Cache transformation 进行数据匹配简单介绍

    本文将讲解Cache transformation的使用方式,并且用Lookup transformation进行匹配. 背景 如下图,我们的产品目标表中有些有尺寸信息有些没有.我们需要用Cache组 ...

  7. 获取多个div,点击第几个,显示第几个

    1.闭包:函数内部又定义了一个函数,内部函数引用外部函数的变量,就构成了闭包. <script type="text/javascript"> var divs = d ...

  8. UVa1368/ZOJ3132 DNA Consensus String

    #include <stdio.h>#include <string.h> int main(){    int a[4][1000]; // A/C/G/T在每列中出现的次数 ...

  9. python列表类型中的陷阱

    在python中对列表使用重复运算符*进行操作时,只是简单的进行了浅复制,内部的结构并没有复制过来,所以下面的例子结果是这样的: >>> lists =[[]]*3 >> ...

  10. PHP新手必须掌握的入门与实战技巧

    作为当今主流的开发语言,PHP集简单.免费.高效等特点于一身.对于想加入PHP大军的新手来说,从何学起.如何学习? 你需要掌握PHP的基础知识.常用功能模块.面向对象.MVC等相关技能.学会了这些技能 ...