python学习day9
目录
一、队列
二、生产者消费者模型
三、协程
四、select\poll\epoll
五、paramiko
六、mysql API调用
一、队列(queue)
队列分以下三种:
class queue.Queue(maxsize=0) #先入先出
class queue.LifoQueue(maxsize=0) #last in fisrt out
class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列
代码如下:
- import queue
- class Foo(object):
- def __init__(self,n):
- self.n = n
- #先进先出
- q = queue.Queue(maxsize=3)
- # q.get(timeout=3) #当队列为空时,get值会阻塞,加timeout参数后,会报错
- # q.get_nowait() #与上面一样的效果
- q.put([1,2,3])
- q.put(Foo(1))
- data = q.get_nowait()
- data2 = q.get_nowait()
- print(data,type(data))
- print(data2,type(data2))
- #输出结果
- # [1, 2, 3] <class 'list'>
- # <__main__.Foo object at 0x000001E060337278> <class '__main__.Foo'>
- print("-----------------")
- print(q.full()) #判断队列里数据是否满了,满为True,未满为False。
- print(q.qsize())#查看现在队列的大小(队列中有多少个数据)
- print(q.empty())#判断队列是否为空
- print("---------------")
- #先入后出
- q = queue.LifoQueue(maxsize=3)
- q.put(1)
- q.put(2)
- q.put(3)
- print(q.get_nowait())
- print(q.get_nowait())
- print(q.get_nowait())
- #输出结果
- #
- #
- #
- print("---------------")
- #可设施优先级的队列
- q = queue.PriorityQueue(maxsize=5)
- q.put((15,1))
- q.put((5,2))
- q.put((7,3))
- q.put((1,[1,2,3]))
- print(q.get())
- print(q.get())
- print(q.get())
- print(q.get())
- #输出结果
- # (1, [1, 2, 3])
- # (5, 2)
- # (7, 3)
- # (15, 1)
二、生产者消费者模型
- import queue,threading
- import time,random
- q = queue.Queue()
- def producer(name):
- count = 0
- while q.qsize() < 20:
- time.sleep(random.randrange(4))
- q.put(count)
- print("producer %s has produced %s baozi.." %(name,q.qsize()))
- count += 1
- def consumer(name):
- count = 0
- while count <20:
- time.sleep(random.randrange(3))
- if not q.empty():
- data2 = q.get_nowait()
- print('\033[32;1mconsumer %s has eat %s baozi...\033[0m' %(name,count))
- else:
- print("-----no baozi anymore-----")
- count += 1
- p1 = threading.Thread(target=producer,args=("XiaoLi",))
- p2 = threading.Thread(target=producer,args=("XiaoMin",))
- c1 = threading.Thread(target=consumer,args=("PangZi",))
- p1.start()
- p2.start()
- c1.start()
三、协程
线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;
协程的好处:
- 无需线程上下文切换的开销
- 无需原子操作锁定及同步的开销
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
缺点:
- 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
- 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
yield实现代码:
- import time,queue
- def consumer(name):
- print("--->starting eating baozi...")
- while True:
- new_baozi = yield
- print("[%s] is eating baozi %s" %(name,new_baozi))
- def producer():
- r = con.__next__()
- r = con2.__next__()
- n = 0
- while n < 5:
- n+=1
- con.send(n)
- con2.send(n)
- print("\033[32;1m[producer]\033[0m is making baozi %s"%n)
- if __name__ == '__main__':
- con = consumer("c1")
- con2 = consumer("c2")
- p = producer()
Greenlet实现代码:
- from greenlet import greenlet
- def test1():
- print("")
- gr2.switch()
- print("")
- gr2.switch()
- def test2():
- print("")
- gr1.switch()
- print("")
- gr1 = greenlet(test1)
- gr2 = greenlet(test2)
- gr1.switch()
Gevent实现代码:
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
- import gevent
- def foo():
- print('\033[31;1mRunning in foo\033[0m')
- gevent.sleep(1)
- print("\033[31;1mExplicit context switch to foo again\033[0m")
- def bar():
- print('\033[32;1mRunning in foo\033[0m')
- gevent.sleep(1)
- print("\033[32;1mExplicit context switch to foo again\033[0m")
- def ex():
- print('\033[33;1mRunning in foo\033[0m')
- gevent.sleep(1)
- print("\033[33;1mExplicit context switch to foo again\033[0m")
- gevent.joinall(
- [
- gevent.spawn(foo),
- gevent.spawn(bar),
- gevent.spawn(ex),
- ]
- )
上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn
。 初始化的greenlet列表存放在数组threads
中,此数组被传给gevent.joinall
函数,后者阻塞当前流程,并执行所有给定的greenlet。执行流程只会在 所有greenlet执行完后才会继续向下走。
遇到IO阻塞时会自动切换任务
- 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/'),
- ])
通过gevent实现单线程下的多socket并发
server端
- import gevent
- from gevent import socket,monkey
- monkey.patch_all()
- def server(port):
- s = socket.socket()
- s.bind(('0.0.0.0', 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)
- s.send(data)
- if not data:
- s.shutdown(socket.SHUT_WR)
- except Exception as ex:
- print(ex)
- finally:
- s.close()
- if __name__ == '__main__':
- server(8001)
client 端
- import socket
- HOST = 'localhost' # The remote host
- PORT = 8001 # The same port as used by the server
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect((HOST, PORT))
- while True:
- msg = bytes(input(">>:"),encoding="utf8")
- s.sendall(msg)
- data = s.recv(1024)
- #print(data)
- print('Received', repr(data))
- s.close()
四、select\selectors\poll\epoll
select、poll、epoll区别:
select:
select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import select
- import socket
- import sys
- import queue
- # Create a TCP/IP socket
- server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建socket实例
- server.setblocking(False) #设置套接字为非阻塞
- # Bind the socket to the port
- server_address = ('localhost', 20000) #设置通信地址
- print(sys.stderr, 'starting up on %s port %s' % server_address) #如果有错误,打印错误
- server.bind(server_address) #绑定通信地址
- # Listen for incoming connections
- server.listen(5) #最大监听5个链接
- # Sockets from which we expect to read
- #select()会监控三个通信列表,
- inputs = [ server ] #定义一个所有的输入
- # Sockets to which we expect to write
- outputs = [ ] #定义一个所有的输出
- message_queues = {}
- while inputs: #客户端过来的所有实例,都放到inputs里,要使inputs为True,将server放入
- # Wait for at least one of the sockets to be ready for processing
- print( '\nwaiting for the next event')
- readable, writable, exceptional = select.select(inputs, outputs, inputs,2) #将三个list传给select后,select会返回三个新的list,分别为可读,可写,异常。
- #
- # Handle inputs
- for s in readable: #循环readable,里面有当前所有链接和server,如果server返回到readable里,代表着有新连接,server就绪。
- if s is server: #new connection #如果server就绪,则有新链接
- # A "readable" server socket is ready to accept a connection
- connection, client_address = s.accept() #接收新链接
- print('new connection from', client_address) #打印
- connection.setblocking(False) #设置新链接为非阻塞
- inputs.append(connection) #将新连接存入inputs里,当下次select时,检测此链接,若有数据则会返回此链接,则接受
- # Give the connection a queue for data we want to send
- message_queues[connection] = queue.Queue() #生成一个此链接的队列,放入message_queues字典
- else: #如果不是server,代表有数据过来
- data = s.recv(1024) #接受数据
- if data: #如果data有数据
- # A readable client socket has data
- print(sys.stderr, 'received "%s" from %s' % (str(data,'utf8'), s.getpeername()) ) #打印data
- message_queues[s].put(str(data,'utf8')) #把data放入字典中相应的链接列表
- # Add output channel for response
- if s not in outputs: #如果此链接不再outputs里
- outputs.append(s) #把新的链接放入outputs
- else: #如果data没有数据,(出错了)
- # Interpret empty result as closed connection
- print('closing', client_address, 'after reading no data') #打印
- # Stop listening for input on the connection
- if s in outputs: #如果链接在outpus里
- outputs.remove(s) #既然客户端都断开了,我就不用再给它返回数据了,所以这时候如果这个客户端的连接对象还在outputs列表中,就把它删掉
- inputs.remove(s) #inputs中也删除掉
- s.close() #把这个连接关闭掉
- # Remove message queue
- del message_queues[s] #把此链接在字典中的列表也删除
- # Handle outputs
- for s in writable: #循环发送队列,查找这个链接
- try:
- next_msg = message_queues[s].get_nowait() #获取发送的数据
- except queue.Empty: #如果为空
- # No messages waiting so stop checking for writability.
- 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,'utf8')) #发送数据给客户端
- # Handle "exceptional conditions"
- for s in exceptional: #客户端断开后,句柄错误,返回到exceptional
- print('handling exceptional condition for', s.getpeername() )
- # Stop listening for input on the connection
- inputs.remove(s) #删除inputs中的句柄
- if s in outputs: #如果句柄在outputs中
- outputs.remove(s) #将outputs中的句柄删除
- s.close() #关闭链接
- # Remove message queue
- del message_queues[s] #删除此链接在message_queues中的列表
select_server示例
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import socket
- import sys
- #消息列表
- messages = [ 'This is the message. ',
- 'It will be sent ',
- 'in parts.',
- ]
- server_address = ('localhost', 20000) #设置通信地址
- # Create a TCP/IP socket
- #配置链接组
- 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),
- ]
- # Connect the socket to the port where the server is listening
- print(sys.stderr, 'connecting to %s port %s' % server_address) #打印链接信息
- for s in socks: #循环链接配置组
- s.connect(server_address) #链接服务器
- for message in messages: #循环消息列表
- # Send messages on both sockets
- for s in socks: #循环链接组
- print(sys.stderr, '%s: sending "%s"' % (s.getsockname(), message)) #打印链接信息与消息
- s.send(bytes(message,"utf8")) #向服务器端发送消息
- # Read responses on both sockets
- for s in socks: #循环链接组
- data = s.recv(1024) #接受服务端发来的数据
- print(sys.stderr, '%s: received "%s"' % (s.getsockname(), str(data,'utf8'))) #打印消息
- if not data: #如果接受的数据为空
- print(sys.stderr, 'closing socket', s.getsockname()) #打印出错信息
- s.close() #关闭连接
select_client示例
selectors:
This module allows high-level and efficient I/O multiplexing, built upon the select module primitives. Users are encouraged to use this module instead, unless they want precise control over the OS-level primitives used.
该模块允许高层次和高效率的输入/输出复用,建立在选择模块原语。用户被鼓励使用这个模块,除非他们想要精确控制操作系统级的原语。
- import selectors
- import socket
- sel = selectors.DefaultSelector()
- def accept(sock, mask):
- conn, addr = sock.accept() # Should be ready
- print('accepted', conn, 'from', addr)
- conn.setblocking(False)
- sel.register(conn, selectors.EVENT_READ, read)
- def read(conn, mask):
- data = conn.recv(1000) # Should be ready
- if data:
- print('echoing', repr(data), 'to', conn)
- conn.send(data) # Hope it won't block
- else:
- print('closing', conn)
- sel.unregister(conn)
- conn.close()
- sock = socket.socket()
- sock.bind(('localhost', 10000))
- sock.listen(100)
- sock.setblocking(False)
- sel.register(sock, selectors.EVENT_READ, accept)
- while True:
- events = sel.select()
- for key, mask in events:
- callback = key.data
- callback(key.fileobj, mask)
selectors示例
poll:
poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。
epoll:
直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。
epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。
另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。
五、paramiko
执行远程命令:
- import paramiko
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- ssh.connect("某IP地址",22,"用户名", "口令(密码)")
- stdin, stdout, stderr = ssh.exec_command("你的命令")
- print stdout.readlines()
- ssh.close()
上传文件到远程:
- import paramiko
- t = paramiko.Transport(("某IP地址",22))
- t.connect(username = "用户名", password = "口令")
- sftp = paramiko.SFTPClient.from_transport(t)
- remotepath='/tmp/test.txt'
- localpath='/tmp/test.txt'
- sftp.put(localpath,remotepath)
- t.close()
从远端下载文件:
- import paramiko
- t = paramiko.Transport(("某IP地址",22))
- t.connect(username = "用户名", password = "口令")
- sftp = paramiko.SFTPClient.from_transport(t)
- remotepath='/tmp/test.txt'
- localpath='/tmp/test.txt'
- sftp.get(remotepath, localpath)
- t.close()
六、MySQL操作
mysql基本操作
1、数据库操作
- show databases;
- use [databasename];
- create database [name];
2、数据表操作
- show tables;
- create table students
- (
- id int not null auto_increment primary key,
- name char(8) not null,
- sex char(4) not null,
- age tinyint unsigned not null,
- tel char(13) null default "-"
- );
3、数据操作
- insert into students(name,sex,age,tel) values('alex','man',18,'151515151')
- delete from students where id =2;
- update students set name = 'sb' where id =1;
- select * from students
4、其他
- 主键
- 外键
- 左右连接
- mysql API操作
- 插入数据
- import MySQLdb
- conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='',db='s12')
- cur = conn.cursor()
- reCount = cur.execute('insert into day9(Name,Address) values(%s,%s)',('tom','usa'))
- conn.commit()
- cur.close()
- conn.close()
- print reCount
批量添加
- import MySQLdb
- conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='',db='s12')
- cur = conn.cursor()
- li =[
- ('tonny','cn'),
- ('xiaoming','cn'),
- ]
- reCount = cur.executemany('insert into day9(Name,Address) values(%s,%s)',li)
- conn.commit()
- cur.close()
- conn.close()
- print reCount
注意:cur.lastrowid
删除数据
- import MySQLdb
- conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='',db='s12')
- cur = conn.cursor()
- reCount = cur.execute('delete from day9')
- conn.commit()
- cur.close()
- conn.close()
- print reCount
修改数据
- import MySQLdb
- conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='',db='s12')
- cur = conn.cursor()
- reCount = cur.execute('update day9 set Name = %s',('alin',))
- conn.commit()
- cur.close()
- conn.close()
- print reCount
查询数据
- import MySQLdb
- conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='',db='s12')
- cur = conn.cursor()
- reCount = cur.execute('select * from day9')
- res = cur.fetchone() #查询一条
- #res = cur.fetchall() #查询全部
- #res = cur.fetchmany(3) #查询几条
- print(res)
- conn.commit()
- cur.close()
- conn.close()
- print reCount
回滚操作
- import MySQLdb
- conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='',db='s12')
- cur = conn.cursor()
- reCount = cur.execute('insert into day9(Name,Address) values(%s,%s)',('tom','usa'))
- reCount = cur.execute('insert into day9(Name,Address) values(%s,%s)',('cat','hk'))
- conn.rollback()#回滚操作
- conn.commit()
- cur.close()
- conn.close()
- print reCount
python学习day9的更多相关文章
- Python学习-day9 线程
这节内容主要是关于线程的学习 首先要了解的什么是进程,什么是线程 进程与线程 什么是进程(process)? 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称 ...
- python学习Day9 内存管理
复习 :文件处理 1. 操作文件的三步骤:-- 打开文件:此时该文件在硬盘的空间被操作系统持有 | 文件对象被应用程序持用 -- 操作文件:读写操作 -- 释放文件:释放操作系统对文件在硬盘间的持有 ...
- python学习day9 字符编码和文件处理
1.字符编码 x='上' #unicode的二进制--------->编码-------->gbk格式的二进制 res=x.encode('gbk') #bytes 字节类型 print( ...
- python学习-Day9
目录 记忆不清点回顾 今日概要 今日内容 大作业讲解 字符编码实际应用 编码与解码 如何解决乱码的问题 文件操作简介 什么是文件 代码操作文件 代码操作文件的流程 基本语法结构 使用关键字打开文件 w ...
- Python学习day9 函数Ⅰ(基础)
函数Ⅰ(基础) 三目运算 基本结构 v = 前面 if 条件 else 后面 #条件为真v=前面,条件为假v=后面.#等同于if 条件: v = '前面'else: v = '后面' ...
- 【目录】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 ...
随机推荐
- PyQt4.11.3(python3.4+QT4)ui文件生成py文件
最近开始接触学习Python,所以想用QT弄个窗体程序出来玩玩,环境是Python3.4.2.PyQt4.11.3-Py3.4.Win7.用PyQt自带的Designer设计出一个窗体ui文件后,需要 ...
- wordpress教程之修改上传文件大小限制
1. 修改apache配置文件 php.ini upload_max_filesize = 64M post_max_size = 64M max_execution_time = 300 //上 ...
- 前端MVVM学习之KnockOut(二)
现在开始学习Knockout并且做个简单的例子. Knockout是建立在以下三个核心功能之上的: 1.Observables and dependency tracking(属性监控与依赖跟踪) 2 ...
- Oracle中使用escape关键字实现like匹配特殊字符,以及&字符的转义
http://blog.chinaunix.net/uid-26896647-id-3433968.html http://soft.chinabyte.com/database/398/124298 ...
- QWidget可以设置QStyle,它可以绘制很多东西(具体内容没研究,待续)
QStyle * QWidget::style() const See also QWidget::setStyle(), QApplication::setStyle(), and QApplica ...
- javaWeb Cache技术――OSCache(转-全)
什么是osCache? 它是:http://baike.baidu.com/view/1835163.htm?fr=aladdin OSCache使用指南 一.下载安装 OSCache是一个基于web ...
- sizeof与类,继承,virtual的种种(整理)
对虚继承层次的对象的内存布局,在不同编译器实现有所区别. 首先,说说GCC的编译器. 它实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针. clas ...
- LeeCode-Two Sum
Given an array of integers, find two numbers such that they add up to a specific target number. The ...
- Java中取小数点后两位(四种方法)
摘自http://irobot.iteye.com/blog/285537 Java中取小数点后两位(四种方法) 一 Long是长整型,怎么有小数,是double吧 java.text.D ...
- github教程--廖雪峰的官方网站
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000