Python多线程
进程
是程序的一次执行。每个进程都有自己的地址空间,内存,数据线及其它记录琪运行轨迹的辅助数据
线程
所有线程运行在同一个进程当中,共享相同的运行环境
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
多线程
多线程类似于同时执行多个不同程序
多线程运行有如下优点
①使用线程可以把占据长时间的程序中的任务放到后台去处理
②程序的运行速度可能加快
③在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,可以释放一些珍贵的资源如内存占用等等
Python 线程中常用的两个模块为
①thread
②threading(推荐使用)
thread 模块已被废弃。用户可以使用 threading 模块代替。
实验
看看以下实例,更容易理解哦
一、简单输出
start_new_thread(funtion,args kwargs=None)
产生一个线程,在新的线程中用指定的参数和可选的kwargs来调用这个函数。
注意:使用这个方法时,一定要加time.sleep(),否则线程可能不执行
import thread
import time
def func1():
print 'Hello world %s\n'%time.ctime()
def main():
thread.start_new_thread(func1,())
thread.start_new_thread(func1,())
thread.start_new_thread(func1,())
thread.start_new_thread(func1,())
//该线程同一时间执行
time.sleep(2)
if __name__ == '__main__':
main()
二、利用系统ping对本地进行一个探测
import thread
import time
from subprocess import Popen,PIPE //调用系统用于直接执行系统命令
def func1():
check = Popen('ping 127.0.0.1',shell=True,stdin=PIPE,stdout=PIPE)
// Popen函数指定shell=True即可,linux下参数executable将指定程序使用的shell,windows下无须指定。
data = check.stdout.read()
//对返回包进行读取显示
print data
func1()
三、在多线程基础上对内网c段进行一个扫描
import thread
import time
from subprocess import Popen,PIPE
def func1(ip):
check = Popen('ping '+ ip,shell=True,stdin=PIPE,stdout=PIPE)
data = check.stdout.read()
//为了方便,利用TTL路由跳数对其进行判断是否存活/回显
if 'TTL' in data:
print '%s is up at %s'%(ip,time.ctime())
def main():
for i in range(1,255):
ip = "192.168.101."+str(i)
thread.start_new_thread(func1,(ip,))
//将ip形参传入func()
time.sleep(0.1)
if __name__ == '__main__':
main()
(可以看到thread在多线程扫描时不受控制,并没有按顺序去扫描,而是通过“先收到先输出”的方式显示出来)
四、采用threading
threading模块 —— 解决了线程数可控的问题
import threading
import time
# from subprocess import Popen,PIPE
def func1(key):
print 'Hello %s:%s\n'%(key,time.ctime())
def main():
threads = []
keys = ['zhangsan','lisi','123456']
threads_count = len(keys) //数组长度 --- 线程数
//将数组以线程形式返回给func1()
for i in range(threads_count):
thread = threading.Thread(target=func1,args=(keys[i],))
//并且将线程添加到新的数组
threads.append(thread)
for i in range(threads_count):
threads[i].start()
for i in range(threads_count):
threads[i].join()
if __name__ == '__main__':
main()
五、多线程访问某度(线程别太大,做个实例示范下而已)
import threading
import time
import requests
# from subprocess import Popen,PIPE
def func1():
time_start = time.time()
r = requests.get(url='http://www.baidu.com')
times = time.time()-time_start
print ('Status:%s —— %s ——%s\n'%(r.status_code,times,time.ctime()))
def main():
threads = []
threads_count = 10 //调节线程数
for i in range(threads_count):
thread = threading.Thread(target=func1,args=())
threads.append(thread)
for i in range(threads_count):
threads[i].start()
for i in range(threads_count):
threads[i].join()
if __name__ == '__main__':
main()
六、生产者-消费者问题和queue模块
—— 解决生产参数和计算结果时间都不确定的问题
queue模块的FIFO队列先进先出。LIFO类似于堆。即先进后出。还有一种是优先级队列级别越低越先出来。
针对这三种队列分别有三个构造函数
class Queue.Queue(maxsize) FIFO
class Queue.LifoQueue(maxsize) LIFO
class Queue.PriorityQueue(maxsize) 优先级队列
queue模块( qsize(),empty(),full(),put(),get() )
完美搭档,queue + threading
# -*- encoding:gbk -*-
import threading
import time
#import requests
from queue import Queue
from subprocess import Popen,PIPE
class DoRun(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self._queue = queue
def run(self):
while not self._queue.empty():
ip = self._queue.get() //从队列拿出ip
check = Popen('ping '+ ip,shell=True,stdin=PIPE,stdout=PIPE)
data = check.stdout.read()
//坑!!因为用的python3,这里通过gbk对中文进行转码
data_str = str(data,'gbk')
if 'TTL' in data_str:
print ('%s is up at %s'%(ip,time.ctime()))
def main():
threads = []
threads_count = 10
queue = Queue()
for i in range(1,255):
queue.put('192.168.101.'+str(i)) //将ip字符串添加到queue队列中
for i in range(threads_count):
threads.append(DoRun(queue))
for i in threads:
i.start()
for i in threads:
i.join()
if __name__ == '__main__':
main()
GOT IT!
******************************************************
小实验小结,具体测试利用方式需根据具体实践场景~