实现可中断的线程

在《从nginx日志读取URL来做性能测试》(http://san-yun.iteye.com/blog/1679215)这篇文章中我实现了一个python多线程来做性能测试,但存在一个问题,线程不可中断,包括两方面:
1. 用户通过kill命令来中断
2. 程序满足某种条件中断(比如测试量大于1000则退出)

下面是我的实现:

# -*- coding: utf-8 -*-
import re
import urllib2
import json
import threading
import Queue
import os
import time
from time import sleep
from threading import Lock
from signal import signal,SIGTERM,SIGINT,SIGQUIT

class Executor:
def __init__(self,size):
self.queue = Queue.Queue()
self.tasks = []
self.running = True

for i in range(size):
t = Task(self.queue)
t.setDaemon(True)
t.start()
self.tasks.append(t)

self._signal()

def _signal(self):
signal(SIGTERM,self._exit)
signal(SIGINT,self._exit)
signal(SIGQUIT,self._exit)


def _exit(self,a=None,b=None):
print 'clean'
self.cancel()

def cancel(self):
for task in self.tasks:
while not task.cancel():
pass

self.running = False
self.onCancel()

def submit(self,call):
self.queue.put(call)

def join(self):
#self.queue.join() queue.join()会阻塞,所以不用
while self.running and not self.queue.empty():
sleep(0.1)
if self.cancelTrigger():
self.cancel()

def setCancelTrigger(self,cancelTrigger):
self.cancelTrigger = cancelTrigger

def setOnCancel(self,onCancel):
self.onCancel = onCancel


class Task(threading.Thread):

def __init__(self,queue):
threading.Thread.__init__(self)
self.queue = queue
self.running = True
self.canceled = False

def cancel(self):
self.canceled=True
return self.isCanceled()

def isCanceled(self):
return self.running==False

def run(self):
while self.running:
call = self.queue.get()
call.run()
self.queue.task_done()
if self.canceled:
self.running = False


客户端使用:

host = "http://7.s.duitang.com"

thread_count = 10 #并发数
max_count=100 #运行次数

total = 0
fail = 0
avg = 0
lock = Lock()

def cancelTrigger():
return total>=max_count

def onCancel():
print 'total %s'%total
print 'fail %s'%fail
print 'avg %s'%(avg/total)

if __name__ == "__main__":
f = open("napi","r")
executor = Executor(thread_count)
executor.setCancelTrigger(cancelTrigger)
executor.setOnCancel(onCancel)
analysis(f.readlines(),executor)
executor.join()



在实现的时候比较纠结的点:
1. Task如果不是daemon会导致任务永远不会停止,但是如果Task是daemon线程,main线程结束之后daemon就结束了。所以这时需要实现一个join()来阻塞main线程:

def join(self):
#self.queue.join() queue.join()会阻塞,所以不用
while self.running and not self.queue.empty():
sleep(0.1)
if self.cancelTrigger():
self.cancel()


2. 线程应该可cancel的,之前是直接修改while isrunning的变量,但这样会导致task其实还没有完成的停止下来。所以对于task我引入两个变量来实现安全的停止。



def cancel(self):
for task in self.tasks:
while not task.cancel():
pass

self.running = False
self.onCancel()

def cancel(self):
self.canceled=True
return self.isCanceled()

def run(self):
while self.running:
call = self.queue.get()
call.run()
self.queue.task_done()
if self.canceled:
self.running = False


3.对于signal专门写了一片文章记录()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值