python第九周:paramiko多线程、队列
1.paramiko模块
用处:连接远程服务器并执行相关操作
使用方法:
SSHClient:连接远程服务器并执行基本命令
import paramiko #创建SSH对象
ssh = paramiko.SSHClient()
#允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#连接服务器
ssh.connect(hostname="cl.salt.com",port=22,username="Mr Wu",password=123456)
#执行命令
stdin,stdout,stderr = ssh.exec_command("df") #标准输入、标准输出、标准错误
#获取命令结果
res,err = stdout.read(),stderr.read()
result = res if res else err
print(result)
#关闭连接
ssh.close()
SSHFtp:连接远程服务器并执行上传下载功能
import paramiko
#建立连接
transport = paramiko.Transport(("hostname",22))
transport.connect(username="Mr Wu",password="")
#TCP/IP等协议实在SFTPClient中定义的
sftp = paramiko.SFTPClient.from_transport(transport)
#将本地文件location.py上传至服务器 /tmp/test.py
sftp.put("/tmp/location.py","/tmp/test.py")
#将远程文件remove_path 下载到本地 local_path
sftp.get("remove_path","local_path")
transport.close()
SSH_RSA:基于公钥密钥进行连接
RSA:非对称密钥验证
公钥:保存在要连接的服务器
私钥:保存在本地机器
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa') #创建SSH对象
ssh = paramiko.SSHClient()
#允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#连接服务器
ssh.connect(hostname="cl.salt.com",port=22,username="Mr Wu",key_filename=private_key)
#执行命令
stdin,stdout,stderr = ssh.exec_command("df")
#获取命令结果
res,err = stdout.read(),stderr.read()
result = res if res else err
print(result.decode())
2.进程:
什么是进程:程序的执行实例称为进程。
每个进程都提供执行程序所需的资源。 进程具有虚拟地址空间,可执行代码,系统对象的打开句柄,安全上下文,唯一进程标识符,环境变量,优先级类,最小和最大工作集大小以及至少一个执行线程。 每个进程都使用单个线程启动,通常称为主线程,但可以从其任何线程创建其他线程。
进程的特点:进程之间的内存是相互独立的
要操作CPU,必须通过线程
进程之间不能直接通信,必须通过中间代理
创建子进程就是对父进程进行一次克隆
进程只能操作它的子进程,不能操作它的父进程
对父进程的修改不会对子进程产生影响
3.线程:
什么是线程:操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程的实际运作单位,一条线程指的是进程中的一个单一顺序的控制流,一个进程可以并发多个线程,每个线程可以执行不同的任务。
线程就是一段可执行的上下文,CPU运行时就不断切换上下文来执行不同的线程,当一个线程没有执行完毕时,寄存器会保存可执行的上下文的中断的位置,当CPU又切换到这段上下文时,就从中断位置继续执行
线程的特点:是操作系统的最小的调度单位,是一串指令的集合
所有在同一进程里的线程共享同一块内存空间
一个线程可以控制和操作同一进程里的其他线程
对主线程的修改可能会影响其他的线程
4.python GIL(Global Interpreter Lock)
全局解释器锁:在python中,全局解释器锁是一个互斥锁,它可以防止多个本机线程同时执行python字节码,这种锁是必要的,因为python线程调用的是操作系统的原生系统,cpython的内存管理不是线程安全的。
全局解释器锁是历史遗留问题:
这是python的内存python解释器里有一个独立的线程,每过一段时间它起wake up做一次全局轮询看看哪些内存数据是可以被清空的,此时你自己的程序 里的线程和 py解释器自己的线程是并发运行的,假设你的线程删除了一个变量,py解释器的垃圾回收线程在清空这个变量的过程中的clearing时刻,可能一个其它线程正好又重新给这个还没来及得清空的内存空间赋值了,结果就有可能新赋值的数据被删除了,为了解决类似的问题,python解释器简单粗暴的加了锁。
所以由于GIL的存在,python并不能利用cpu多核的特性,在微观层面上,python并不是真正的多线程,在同一时刻只能有一个线程在运行。
python threading模块:
线程的两种调用方式:
直接调用:
实例化一个线程:t = threading.Thread()
import threading,time
#循环启动50个线程
def run(n):
time.sleep(2)
print("task:",n,threading.current_thread())
for i in range(50):
t = threading.Thread(target=run,args=("t%s"%i,))
t.start()
继承式调用:
import threading
class MyThread(threading.Thread):
def __init__(self,n):
super(MyThread,self).__init__()
self.n = n
def run(self):
print("running task",self.n) t1 = MyThread("t1")
t2 = MyThread("t2") t1.start()
t2.start()
t.Join()
阻塞:主线程必须等待线程t执行完毕后才能继续执行
import threading,time
def run(n):
time.sleep(2)
print("task:",n,threading.current_thread())
start_time = time.time()
t_list = [] #存放线程实例
for i in range(10):
t = threading.Thread(target=run,args=("t%s"%i,))
t.start()
t_list.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里
for t in t_list:
t.join()
end_time = time.time()
print("=========all threads has finished....")
print("cost:",end_time - start_time,threading.current_thread())
#整个程序是一个主线程,for循环内是子线程,主线程与子线程并发运行
#output:
'''
task: t0 <Thread(Thread-1, started 6448)>
task: t1 <Thread(Thread-2, started 10080)>
task: t2 <Thread(Thread-3, started 2736)>
task: t3 <Thread(Thread-4, started 7072)>
task: t4 <Thread(Thread-5, started 7704)>
task: t6 <Thread(Thread-7, started 1280)>
task: t5 <Thread(Thread-6, started 1520)>
task: t8 <Thread(Thread-9, started 3764)>
task: t7 <Thread(Thread-8, started 4136)>
task: t9 <Thread(Thread-10, started 2444)>
=========all threads has finished....
cost: 2.0088112354278564 <_MainThread(MainThread, started 6208)> '''
t.setBaemon(True)
将线程t设置为守护线程,整个程序在非守护线程执行结束时就结束,不会等待守护进程
注:由守护进程创建的其他进程,在非守护进程结束时也会结束,不管其是否完成任务
import threading,time
def run(n):
time.sleep(2)
print("task:",n,threading.current_thread())
start_time = time.time()
for i in range(50):
t = threading.Thread(target=run,args=("t%s"%i,))
t.setDaemon(True)
t.start()
end_time = time.time()
print("=========all threads has finished....")
print("cost:",end_time - start_time,threading.current_thread())
#整个程序是一个主线程,for循环内是子线程,主线程与子线程并发运行
#整个程序在非守护线程执行结束时就结束,不会等待守护进程
注:由守护进程创建的其他进程,在非守护进程结束时也会结束,不管其是否完成任务
#output:
'''
=========all threads has finished....
cost: 0.03975486755371094 <_MainThread(MainThread, started 10208)>
'''
线程锁:
设count = 0,当我们启用50个线程去执行count += 1时。按理来说,由于GIL的存在,这些线程其实是串行的,计算出的最终count的值应该等于50,但是在实际程序运行时,count的值常常会小于50。这与python GIL的运行原理有关,当CPU大概执行一百多条命令时python解释器就会释放全局解释器锁,这样就可能导致某两个线程返回的是同一个值(其中一个线程还没有执行完毕时,python解释器释放了全局解释器锁,导致另一个线程拿到的值是数据池里面没有改变的值)
这个时候我们可以自己设置线程锁,即在一个线程执行完任务count += 1后,才会释放线程锁,其他线程才能申请全局解释器锁。
import threading,time
#实例化一个线程锁
lock = threading.Lock()
num = 0
#当数据量不是特别大时可使用线程锁
def run(n):
lock.acquire() #加锁
global num
num += 1
lock.release() #释放锁
for t in range(50):
t = threading.Thread(target=run,args=(num,))
t.start() print("num:",num)
#output: num: 50
递归锁(Rlock)
import threading,time num,num2 = 0,0
lock = threading.RLock() #递归锁
def run1():
print("grab the first part data")
lock.acquire()
global num
num += 1
lock.release()
return num def run2():
print("grab the second part data")
lock.acquire()
global num2
num2 += 1
lock.release()
return num2 def run3():
lock.acquire()
res = run1()
print("-----between run1 and run2------")
res2 = run2()
lock.release()
print(res,res2) for i in range(2):
t = threading.Thread(target=run3)
t.start() while threading.active_count() != 1:
pass
else:
print("=======all threads done======")
print(num,num2)
#output:
'''
grab the first part data
-----between run1 and run2------
grab the second part data
1 1
grab the first part data
-----between run1 and run2------
grab the second part data
2 2
=======all threads done======
2 2 '''
信号量(semaphore)
线程锁同时允许一个线程更改数据,而信号量是同时允许一定数量的线程更改数据。
注:在设置的信号量线程里,只要有一个线程完成,就会让新的线程进来,直到所有线程运行结束
semaphore = threading.BoundedSemaphore(5) #设置信号量,最大只能设置为5
semaphore.acquire() #申请线程锁
semaphore.release() #释放线程锁
#在设置的信号量线程里,只要有一个线程完成,就会让新的线程进来,保持设置的线程数直到所有线程运行结束
import threading,time def run(n):
semaphore.acquire()
print("run the thread: %s\n"%n)
global num
num += 1
time.sleep(1)
semaphore.release()
if __name__ == '__main__':
num = 0
semaphore = threading.BoundedSemaphore()#最多允许5个线程同时运行
for i in range(20):
t = threading.Thread(target=run,args=(i,))
t.start() while threading.active_count() != 1:
pass
else:
print("-----all threads done-----")
print(num)
计时器(Timer)
此类表示仅在经过一定时间后才应运行的操作。
与线程一样,通过调用start()方法启动计时器。 通过调用thecancel()方法可以停止计时器(在其动作开始之前)。 计时器在执行其操作之前将等待的时间间隔可能与用户指定的时间间隔不完全相同。
import threading
def run():
print("My Name Is Mr Wu!")
t = threading.Timer(10,run)
t.start() #在10秒后输出 My Name Is Mr Wu!
事件(event)
事件是一个简单的同步对象;
事件代表一个内部标志和线程。
事件可以等待设置标志,或者自己设置或清除标志。
简单点来说,事件就是通过设置、清除标志位来实现两个线程之间的交互。
event = threading.Event() #生成一个事件实例
event.clear() #清空标志位
event.set() #设置标志位
event.wait() #等待标志位被设置
程序示例:红灯停、绿灯行。红灯、绿灯的持续时间都是5,当汽车看到红灯的时候停止行驶,当看到绿灯的时候行驶。
import time,threading
event = threading.Event()#生成一个事件实例
def lighter():
count = 0
while True:
if count > 5 and count <= 10:#改成红灯
event.clear()#清空标志位
print("\033[41;1m红灯停\033[0m")
elif count > 10: #改成绿灯
#event.set()
count = 0
else:
event.set()
print("\033[42;1m绿灯行\033[0m")
time.sleep(1)
count += 1 def car(name):
while True:
if event.is_set(): #绿灯行
print("[%s] running...."%name)
time.sleep(1)
else:
print("[%s] sees red light , waiting..."%name)
event.wait()
print("[%s] sees green light , start going..."%name)
car1 = threading.Thread(target=car,args=("Tesla",))
light = threading.Thread(target=lighter)
light.start()
car1.start()
队列(Queue)
当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用。
简单点说,队列就是一个存放数据的容器,线程既可以把数据放进去也可以把数据取出来,以此达到线程交互的目的。
队列的作用:
1.解耦,使程序直接实现松耦合
2.提高处理效率
class queue.Queue(maxsize = 0) #先进先出
class queue.LifoQueue(maxsize = 0) #后进先出
class queue.PriorityQueue(maxsize = 0) #存储数据时可设置优先级
优先级队列的构造函数。 maxsize是一个整数,用于设置可以放入队列的项目数的上限。 达到此大小后,插入将阻止,直到消耗队列项。 如果maxsize小于或等于零,则队列大小为无限大。
exception queue.Bmpty
在对空的Queue对象调用非阻塞get()(或get_nowait())时引发异常。
exception queue.Full
在已满的Queue对象上调用非阻塞put()(或put_nowait())时引发异常。
Queue.qsize() #返回队列的长度
Queue.empty() #return True if enmpty
Queue.full() #return True if full
Queue.put(item,block = True,timeout = None) #取出队列里的数据
当把将数据放入队列中时。 如果block=True且timeout=None(默认值),则在队列为满的时候阻塞,直到队列有空闲区域的时候才能继续放入数据。 如果timeout是一个正数,则队列阻塞最多timeout秒,如果在该时间内队列为满,则会引发Full异常。如果block=False,当队列有空闲区域时,则将数据放在队列中,否则引发Full异常(在这种情况下忽略超时)。
Queue.put_nowait(item)
Equivalent to put(item,False)
.
Queue.get(block = True,timeout = None)
当从队列中取出数据时。 如果block=true且timeout=None(默认值),则在队列为空的时候阻塞,直到队列中有数据时才能继续取出数据。 如果timeout是一个正数,则队列阻塞最多timeout秒,如果在该时间内队列为空,则会引发Empty异常。当block=False,当队列不为空时,则可取出数据,否则引发Empty异常(在这种情况下忽略超时)、
Queue.get_nowait(time)
Equivalent to get(item,False)
.
生产者消费者模型
为什么要使用生产者消费者模式?
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产这消费者模式?
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
程序示例:
import threading,queue,time
q = queue.Queue(maxsize=10)
def producer(name):
count = 1
while True:
q.put("骨头%s"%count)
print("生产了骨头",count)
count += 1
time.sleep(2)
def consumer(name):
#while q.qsize() > 0:
while True:
print("[%s] 取到[%s],并且吃了它...."%(name,q.get()))
time.sleep(1)
p = threading.Thread(target=producer,args=("Alex",))
c = threading.Thread(target=consumer,args=("ChengRongHua",))
c1 = threading.Thread(target=consumer,args=("王森",))
p.start()
c.start()
c1.start()
python第九周:paramiko多线程、队列的更多相关文章
- 20165236 2017-2018-2 《Java程序设计》第九周学习总结
20165236 2017-2018-2 <Java程序设计>第九周学习总结 一.第十三章教材内容总结 1.URL类 URL类是java.net包中的一个重要的类,使用URL创建对象的应用 ...
- python九周周末总结
python九周周末总结 UDP协议 udp协议的交互模式服务端不需要考虑客户端是否退出,你发多少那么他就会按照你发的东西直接去传输给客户端不存在黏包现象 服务端: import socket ser ...
- 一行 Python 实现并行化 -- 日常多线程操作的新思路
春节坐在回家的火车上百无聊赖,偶然看到 Parallelism in one line 这篇在 Hacker News 和 reddit 上都评论过百的文章,顺手译出,enjoy:-) http:// ...
- python 多进程开发与多线程开发
转自: http://tchuairen.blog.51cto.com/3848118/1720965 博文作者参考的博文: 博文1 博文2 我们先来了解什么是进程? 程序并不能单独运行,只有将程 ...
- 20165223《信息安全系统设计基础》第九周学习总结 & 第八周课上测试
目录 [第九周学习总结] 教材内容总结 [第八周课上测试] (一)求命令行传入整数参数的和 (二)练习Y86-64模拟器汇编 (三)基于socket实现daytime(13)服务器和客户端 参考资料 ...
- 20172306 2018-2019-2 《Java程序设计与数据结构》第九周学习总结
20172306 2018-2019-2 <Java程序设计与数据结构>第九周学习总结 教材学习内容总结 无向图 图是由结点和这些结点之间的连接构成 就图来说,结点叫做顶点,结点之间的连接 ...
- 20165223《Java程序设计》第九周Java学习总结
教材学习内容总结 第13章- URL类 InetAddress类 套接字 UDP数据报 广播数据报 Java远程调用(RMI) 教材学习中的问题和解决过程 1. URL类 URL类构造方法: 使用字符 ...
- 20165234 《Java程序设计》第九周学习总结
第九周学习总结 教材内容学习 第十三章 Java 网络编程 URL 类 URL 类是 java.net 包中的一个重要的类,使用URL创建对象的应用程序称为客户端程序. 一个 URL 对象通常包含最基 ...
- 20165235 祁瑛 2018-4 《Java程序设计》第九周学习总结
20165235 祁瑛 2018-4 <Java程序设计>第九周学习总结 教材学习内容总结 URL类 UR类是java.net包中的一个重要类,使用URL创建的对象的应用程序称作称作客户端 ...
随机推荐
- Project Euler:Problem 33 Digit cancelling fractions
The fraction 49/98 is a curious fraction, as an inexperienced mathematician in attempting to simplif ...
- Android HAL模块实现
1. HAL介绍 Android的HAL(Hardware Abstract Layer硬件抽象层)是为了保护一些硬件提供商的知识产权而提出的.是为了避开linux的GPL束缚. 思路是把控制硬件的动 ...
- JS基础之开篇
JavaScript是解释型语言,无需编译就可以随时运行,这样哪怕语法有错误,没有语法错误的部分还是能正确运行. 1.JavaScript能做什么? 01, javaScript可以进行表单验证 如果 ...
- 利用安卓手机搭建WEB服务器
背景介绍 Android是一种基于Linux的自由及开放源代码的操作系统 所以是用安卓来搭建服务器是完全可行的.接下来将教大家如何利用AndroPHP和Feel FTP(或者其他FTP管理器)来在安卓 ...
- 0507-php独立环境的安装与配置
1.在一个纯英文目录下新建三个文件夹 2.安装apache(选择好版本) 过程中该填的按格式填好,其余的只更改安装目录即可 如果报错1901是安装版本的问题. 检查:安装完成后localhost打开为 ...
- html5 窗口之间的通信
一般窗口通信分为三种: iframe嵌套:多个iframe之间通信. 父页面操作子页面元素:oFrame.contentWindow.document.body. 父页面调用子页面方法:oFrame. ...
- layui富文本编译器后台获取图片路径
@RequestMapping("add") public ModelAndView add(News news){ ModelAndView mav = ne ...
- AOP实现参数的判空问题
不想每次都去判断必传的参数是否为空,写代码太繁琐了,正好最近用了AOP实现权限控制,依葫芦画瓢,现在用它实现参数的判空,至于AOP的原理之类,自己百度了解一下吧 1. NullDisable注解 @D ...
- MSSQL:账号无法删除方案
1.查询 EXEC sp_who 'WIN-GBKBCVTG4CN\Administrator' 返回一个表格,其中有列[spid] 2.删除 kill spid
- es优化收藏
Elasticsearch常用优化 https://www.cnblogs.com/zlslch/p/6478773.html Elasticsearch 基础理论 & 配置调优 http:/ ...