Python多线程
在很多时候单线程效率低,满足不了我们的要求,因此采用效率更高的多线程。
thread模块
Python中thread模块提供了线程的支持,能够满足基本的线程和互斥锁的支持,一些thread的基本用法:
#派生一个新的线程,给定args和kwargs来执行function thread.start_new_thread(function,args kwargs=None) #function----->线程函数 #args--------->传递给线程函数的参数 #kwargs------->可选参数 #分配一个锁给对象 thread.allocate_lock() #线程退出一般依靠线程函数的自然结束,但是也可以利用线程函数中的thread.exit() thread.exit() #获取锁对象 lock.accquire(waitflag=1,timeout=1) #如果获取了锁的对象返回1,否则返回0 lock.locked() #释放锁 lock.release() #表示线程活动的方法 thread.run() #表示启动线程的活动 thread.start() #等待线程的中止,或者可选的超时发生 thread.join() #线程同步的开关锁 thread.acquire() thread.release()
含义:产生一个新的函数,在新的线程中用指定的参数去调用,使用的时候前面一定要加time.sleep(),否则线程可能无法执行。
import thread import time def threadTest(): print("Hello world %s"%time.ctime()) def main(): thread.start_new_thread(threadTest,()) time.sleep(2) thread.start_new_thread(threadTest,()) time.sleep(2) if __name__=='__main__': main()
使用thread模块+ping进行存活主机探测:
#coding=utf-8 import thread import time from subprocess import Popen,PIPE def check_ping(): check=Popen(['/bin/bash','-c','ping -c 3 '+'127.0.0.1'],stdin=PIPE,stdout=PIPE) data=check.stdout.read() print(data) check_ping()
此外之前我们在操作系统中学习过生产者和消费者的模型,这个模型可以解决线程数可控与生产参数与计算结果事件都不确定的问题。
使用模块:Thread类与Queue模块
#coding=utf-8 import threading import time def fun1(key): print("Hello %s:%s"%(key,time.ctime())) def main(): threads=[] keys=['zhangsan','lisi','wangmanzi'] threads_count=len(keys) for i in range(threads_count): t =threading.Thread(target=fun1,args=(keys[i],)) threads.append(t) print("No "+str(i)+"thread is"+str(threads)) for i in range(threads_count): threads[i].start() for i in range(threads_count): threads[i].join() main()
使用多线程进行访问网站:
#coding=utf-8 import threading import time import requests def fun1(): time_start=time.time() r=requests.get(url="http://www.bilibili.com") time_end=time.time()-time_start print("Status:%s--%s---%s"%(r.status_code,time_end,time.strftime('%H:%M:%S'))) def main(): threads=[] threads_count=5 for i in range(threads_count): t=threading.Thread(target=fun1,args=()) threads.append(t) for i in range(threads_count): threads[i].start() for i in range(threads_count): threads[i].join() main()
使用多线程+PING进行存活主机探测,可以根据自己的想法来加快进程访问速度
#coding=utf-8 import threading import Queue from subprocess import Popen,PIPE class DoRun(threading.Thread):#继承父类threading.Thread def __init__(self,queue): threading.Thread.__init__(self) self._queue=queue def run(self):#把要执行的代码写道run里面,线程在创建后会直接运行run函数 while not self._queue.empty(): ip=self._queue.get() check_ping = Popen(['/bin/bash','-c','ping -c 2 '+ip],stdin=PIPE,stdout=PIPE) data = check_ping.stdout.read() if 'ttl' in data: print(ip+'is UP') # else: # print(ip+'is Not UP!Not UP!') def main(): threads = [] threads_count = 100 queue = Queue.Queue() for i in range(1,255): queue.put("121.201.42."+str(i)) for i in range(threads_count): threads.append(DoRun(queue)) for i in threads: i.start() for i in threads: i.join() main()
以上的代码看起来很多很多但其实分为三个部分,三个部分结合的功能是多线程检查C段存活主机,把三个部分拆开来看,我们可以更多的了解函数的具体功能。
首先得从线程同步开始,首先代码中使用到与线程有关的函数很多:
import threading #用来引用和线程有关的库 #本次使用到的主要有: #①threading.Thread----->Runoob中说用来继承,我把它当作默认参数使用,在多进程函数里 #②threads[]------------>用来描述线程,必须存在,会对线程进行增删改查 #③threads_count-------->用来描述线程数,越多越快 #③for i in range(threads_counts)-->线程实现同步的根本原因是for函数 #④for i in threads:---->这里没有用到range的原因是因为使用到了队列 #i.start(),i.join()线程的开始与自然结束
第二部分是PING函数的使用方法,其实非常简单,一个是调用库函数,一个是命令执行语句的拼合,主要部分是对命令执行语句的理解:
from subprocess import Popen,PIPE #subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。 #本质是使用subprocess创建进程来进行命令执行 #Popen()方法是subprocess的核心,子进程的创建由他管理 #class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, ) #args:shell命令 #bufsize缓冲区大小,stdin,stdout,stderr,标准输入,输出,错误句柄 # check_ping = Popen(['/bin/bash','-c','ping -c 2 '+ip],stdin=PIPE,stdout=PIPE) #Linux下指定Ping命令的进程,'/bin/bash','-c',注意这个-c千万不能省略,他是吧字串作为完成的命令去执行.
最后一部分是Queue队列,用来实现有序和多进程
#import Queue #queue=Queue.Queue() #queue.put("121.201.42."+str(i))放入队列 #while not self._queue.empty(): #ip=self._queue.get()获取当前队列内容
三者组合逻辑,第一部分提供线程支持服务,第二部分提供命令执行服务,第三部分执行和类似生产者和消费者的行为。