一、如何使用多线程、线程间通信、线程间事件通信
import csv
from xml.etree.ElementTree import Element, ElementTree
import requests
from StringIO import StringIO
from threading import Thread, Event
from Queue import Queue
import os, tarfile
def pretty(e, level=0):
if len(e) > 0:
e.text = '\n' + '\t' * (level + 1)
for child in e:
pretty(child, level + 1)
child.tail = child.tail[:-1]
e.tail = '\n' + '\t' * level
class DownloadThread(Thread):
def __init__(self, sid, queue):
Thread.__init__(self)
self.sid = sid
self.url = 'http://pythonscraping.com/files/MontyPythonAlbums.csv'
self.queue = queue
def download(self):
response = requests.get(self.url, timeout=3)
if response.ok:
return StringIO(response.content)
def run(self):
data = self.download()
self.queue.put((self.sid, data))
class ConverThread(Thread):
def __init__(self, queue, cEvent, tEvent):
Thread.__init__(self)
self.cEvent = cEvent
self.tEvent = tEvent
self.queue = queue
def csvToXml(self, scsv, fxml):
reader = csv.reader(scsv)
headers = reader.next()
headers = map(lambda h: h.replace(' ', ''), headers)
root = Element('Data')
for row in reader:
eRow = Element('Row')
root.append(eRow)
for tag, text in zip(headers, row):
e = Element(tag)
e.text = text
eRow.append(e)
pretty(root)
et = ElementTree(root)
et.write(fxml)
def run(self):
count = 0
while True:
sid, data = self.queue.get()
if sid == -1:
self.tEvent.set()
self.cEvent.wait()
break
if data:
with open(str(sid).rjust(6, '0') + '.xml', 'wb') as wf:
self.csvToXml(data, wf)
count += 1
if count == 3:
self.tEvent.set()
self.cEvent.wait()
self.cEvent.clear()
count = 0
class TarXml(Thread):
def __init__(self, cEvent, tEvent):
Thread.__init__(self)
self.cEvent = cEvent
self.tEvent = tEvent
self.count = 1
self.setDaemon(True)
def tarXml(self):
tfname = str(self.count).rjust(3, '0') + '.tgz'
with tarfile.open(tfname, 'w:gz') as tf:
for fname in os.listdir('.'):
if fname.endswith('.xml'):
tf.add(fname)
os.remove(fname)
if not tf.members:
os.remove(tfname)
self.count += 1
def run(self):
c=1
while True:
self.tEvent.wait()
self.tarXml()
self.tEvent.clear()
self.cEvent.set()
c+=1
queue = Queue()
cEvent = Event()
tEvent = Event()
dThreads = [DownloadThread(i, queue) for i in xrange(1, 8)]
cThread = ConverThread(queue,cEvent,tEvent)
tThread = TarXml(cEvent,tEvent)
for t in dThreads:
t.start()
cThread.start()
tThread.start()
for t in dThreads:
t.join()
queue.put((-1, None))
二、如何使用线程本地数据
import os,cv2,time,struct,threading
from BaseHTTPServer import HTTPServer,BaseHTTPRequestHandler
from SocketServer import TCPServer,ThreadingTCPServer
from threading import Thread,RLock
from select import select
class JpegStreamer(Thread):
def __init__(self,camera):
Thread.__init__(self)
self.cap = cv2.VideoCapture(camera)
self.lock =RLock()
self.pipes = {}
def register(self):
pr,pw =os.pipe()
self.lock.acquire()
self.pipes[pr]=pw
pw = self.pipes.pop(pr)
self.lock.release()
return pr
def unrgister(self,pr):
self.lock.acquire()
self.pips.pop(pr)
self.lock.release()
pr.close()
pw.close()
def capture(self):
cap = self.cap
while cap.isOpened():
ret,frame = cap.read()
if ret:
ret,data =cv2.imencode('.jpg',frame,(cv2.IMWRITE_JPEG_QUALITY,40))
yield data.tostring()
def send(self,frame):
n= struct.pack('l',len(frame))
self.lock.acquire()
if len(self.pipes):
_,pipes,_ =select([],self.pipes.itervalues(),[],1)
for pipe in pipes:
os.write(pipe,n)
os.write(pipe,frame)
self.lock.release()
def run(self):
for frame in self.capture():
self.send(frame)
class JpegRetriever(object):
def __init__(self,streamer):
self.streamer= streamer
self.pipe =streamer.register()
def retrieve(self):
while True:
ns= os.read(self.pipe,8)
n=struct.unpack('l',ns)[0]
data = os.read(self.pipe,n)
yield data
def cleanup(self):
self.streamer.unregister(self.pipe)
class Handler(BaseHTTPRequestHandler):
retriever=None
@staticmethod
def setJpegRetriever(retriever):
Handler.retriever=retriever
def do_GET(self):
if self.retriever is None:
raise RuntimeError('no retriever')
if self.path !='/':
return
self.send_response(200)
self.send_header('Content-type','multipart/x-mixed-replace;boundary=abcde')
self.end_headers()
for frame in self.retriever.retrieve():
self.send_frame(frame)
def send_frame(self,frame):
self.wfile.write('--abcde\r\n')
self.wfile.write('Content-Type:image/jpeg\r\n')
self.wfile.write('Content-Length:%d\r\n\r\n'%len(frame))
self.wfile.write(frame)
if __name__ == '__main__':
streamer = JpegRetriever(0)
streamer.start()
retriever=JpegRetriever(streamer)
Handler.setJpegRetriever(retriever)
print 'start server ...'
httpd = TCPServer(('',9000),Handler)
httpd.sever_forever()
五、如何使用线程池
# 待补充
六、如何使用多进程
# 待补充