Python168的学习笔记7
关于多线程操作。
对于IO操作,如访问网站,写入磁盘这种需要时间等待响应的操作,多个cpu也几乎不能提高效率。
对于CPU密集型操作,如这个格式转换,可以通过多个cpu同时去进行。
但是对于python来讲,python存在GIL全局解释器的锁,导致只有一个python线程能被解释器接收。所以等于python只能对IO操作使用线程操作。
#coding:utf8
import csv
from xml.etree.ElementTree import Element,ElementTree
import requests
from StringIO import StringIO
from test_retractxml import pretty def download(url):
#IO操作很慢,因为不能直接得到数据。如这步:是发送请求,等待数据,在等待的过程中让出CPU,自己睡眠。
response = requests.get(url,timeout=3)
if response.ok:
return StringIO(response.content) def csvToxml(scsv,fxml):
#这是CPU密集型操作,多个CPU可以同时操作
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 handle(sid):
print 'Download ...(%d)' % sid
url = 'http://table.finance.yahoo.com/table.csv?s=%s.sz'
url %= str(sid).rjust(6,'')
rf = download(url)
if rf is None:return print 'Convert to XML...(%d)' % sid
fname = str(sid).rjust(6,'')+'.xml'
with open(fname,'wb') as wf:
csvToxml(rf, wf) from threading import Thread '''
t = Thread(target=handle,args=(1,))
t.start() print 'main thread'
'''
class MyThread(Thread):
def __init__(self,sid):
Thread.__init__(self)
self.sid = sid def run(self):
handle(self.sid) threads = []
for i in xrange(1,11):
t = MyThread(i)
threads.append(t)
t.start() for t in threads:
t.join() print 'main thread'
#t.join()#阻塞函数,保证主线程在所有子线程结束后再退出 '''
#这是串行的方法
for sid in xrange(1,11):
print 'Download ...(%d)' % sid
url = 'http://table.finance.yahoo.com/table.csv?s=%s.sz'
url %= str(sid).rjust(6,'0')
rf = download(url)
if rf is None:continue print 'Convert to XML...(%d)' % sid
fname = str(sid).rjust(6,'0')+'.xml'
with open(fname,'wb') as wf:
csvToxml(rf, wf)
'''
线程间通信,可以用全局变量,但是不够安全,可以用Queue.Queue来存储通信内容。Queue作为线程安全的队列。
#coding:utf8
import requests
import csv
from xml.etree.ElementTree import Element,ElementTree
from test_retractxml import pretty
from threading import Thread
from StringIO import StringIO from Queue import Queue class DownloadThread(Thread): def __init__(self,sid,queue):
Thread.__init__(self)
self.sid = sid
self.url = 'http://table.finance.yahoo.com/table.csv?s=%s.sz'
self.url %=str(sid).rjust(6,'')
self.queue = queue def download(self,url):
response = requests.get(url,timeout=3)
if response.ok:
return StringIO(response.content) def run(self):
print'download',self.sid
data = self.download(self.url)
self.queue.put((self.sid,data)) class ConverThread(Thread):
def __init__(self,queue):
Thread.__init__(self)
self.queue = queue def csvToxml(self,rf,wf):
reader = csv.reader(rf)
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(wf) def run(self):
while True:
sid,data = self.queue.get()
print 'Convert', sid
if sid == -1:
break
if data:
fname = str(sid).rjust(6,'')+'.xml'
with open(fname,'wb') as wf:
self.csvToxml(data, wf) q = Queue()
dThreads = [DownloadThread(i,q) for i in xrange(1,11)]
cThread = ConverThread(q) for t in dThreads:#多个线程下载
t.start() cThread.start()#一个线程处理 for t in dThreads:
t.join() q.put((-1,None))
由于全局锁GIL的存在,无法用多个线程来对cpu密集操作,所以此例子中是1,用多个线程来进行IO操作;2,将所有下载的内容传给1个线程进行转换。他们之间的交换是通过存入Queue这个安全队列里面。
而进程之间的的事件通知,需要调用thread库里的Event。事件的等待是Event.wait(),事件的响应是Event.set(),需要注意的是,set之后事件就不会再wait,需要Event.clear()来重新激活wait。要把等待,响应的逻辑弄清楚。
这节还引入了守护线程setDaemon的概念,当其值为True时 ,其他线程结束时,自身也会结束。
#coding:utf8class DownloadThread(Thread):
****
class ConverThread(Thread):
def __init__(self,queue,cEvent,tEvent):
Thread.__init__(self)
self.queue = queue
self.cEvent = cEvent
self.tEvent = tEvent def csvToxml(self,rf,wf):
**** def run(self):
count = 0
while True:
sid,data = self.queue.get()
print 'Convert', sid
if sid == -1:
self.cEvent.set()
self.tEvent.wait()
break
if data:
fname = str(sid).rjust(6,'')+'.xml'
with open(fname,'wb') as wf:
self.csvToxml(data, wf)
count += 1
if count == 5: #注意这里的逻辑
self.cEvent.set()#激活cEvent,表示转换完成 self.tEvent.wait()#等待tEvent事件完成
self.tEvent.clear()#重新激活tEevent
count = 0
import tarfile
import os class TarThread(Thread):
def __init__(self,cEvent,tEvent):
Thread.__init__(self)
self.count = 0
self.cEvent = cEvent
self.tEvent = tEvent
self.setDaemon(True)#守护线程,其他线程退出后,他也退出 def tarXML(self):
self.count += 1
tfname = '%d.tgz'%self.count
tf = tarfile.open(tfname,'w:gz')#打包命令,打包格式为gz
for fname in os.listdir('.'):#遍历当前文件夹的文件
if fname.endswith('.xml'):#找到.xml结尾的文件
tf.add(fname)#添加到压缩包中
os.remove(fname)#删除掉已添加加的文件
tf.close() if not tf.members:#如果打包文件为空,则删除
os.remove(tfname) def run(self):
while True:
self.cEvent.wait()#等待cEvent事件
self.tarXML()
self.cEvent.clear()#重新激活等待 self.tEvent.set()#激活tEvent,表示完成打包 if __name__ == '__main__':
q = Queue()
dThreads =[DownloadThread(i,q) for i in xrange(1,11)] cEvent = Event()
tEvent = Event() cThread = ConverThread(q,cEvent,tEvent)
tThread = TarThread(cEvent,tEvent)
tThread.start()#注意这里要start线程 for t in dThreads:
t.start()
cThread.start() for t in dThreads:
t.join() q.put((-1,None))
print 'main thread'
本地线程这一章开始之后都是用了python3,我暂时还是想用python2来实现,所以先放一下,以后在回来补充。
线程池:pass
多进程:pass
:pass
Python168的学习笔记7的更多相关文章
- Python168的学习笔记8
#coding:utf8 #斐波那契数列,第三项起,每一项都等于前两项之和 def memo(func): cache = {}#闭包 def wrap(*args): if args not in ...
- Python168的学习笔记6
如何派生内置不可变类型并修改实例化行为. 个人理解,如何派生出自己想要的类. class IntTuple(tuple): def __new__(cls,iterable): g = (x for ...
- Python168的学习笔记5
关于对csv文件的操作. python标准库中有csv的库,使用非常方便. import csv with open('pingan.csv','rb') as rf: reader = csv.re ...
- Python168的学习笔记4
关于普通文本文件的读写 python2.7中,未注明的字符都是以acsii来编码的,而要让字符能够通用,必须声明为unicode. s=u'你好',s.encode('utf8')就是指用utf8来进 ...
- Python168的学习笔记3
list.extend(),可以拓展list,a=(0,1),b=(2,3) a.extend(b),a就变成(0,1,2,3) 分割字符串(除去字符串中的,\/;之类的),如果用str.split( ...
- Python168的学习笔记2
关于for循环,其实质是利用被循环对象的__iter__,或者__getitem__属性接口,由可迭代对象得到迭代器.for循环就是不断调用.next(),直到最终捕获到stop. import re ...
- Python168的学习笔记1
在对list的条件选择有两种常用方法,直接使用filter函数,就是filter(func,sequence);另外一种就是迭代操作,类似 x for x in sequence func.这两种方法 ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
随机推荐
- xmlHttpRequest 跨域和上传或下载进度条
跨域 XMLHttpRequest 请求 普通网页能够使用XMLHttpRequest对象发送或者接受服务器数据, 但是它们受限于同源策略. 扩展可以不受该限制. 任何扩展只要它先获取了跨域请求许可, ...
- 使用IntelliJ IDEA新建maven的javaWeb项目部署,启动访问index,jsp页面
对于用惯了eclipse的人,idea其实还挺不一样的,也是摸索了很久,看了好多博客,这里就记录一下,以后肯定经常用!,不过使用熟练了,功能确实非常强大,真的牛! 1 新建maven项目,配置好目录结 ...
- Word Ladder I & II
Word Ladder I Given two words (start and end), and a dictionary, find the length of shortest transfo ...
- 01-Coredump核心转存&&Linux程序地址分析【转】
转自:http://www.itwendao.com/article/detail/404132.html 目录(?)[-] 一Core Dump核心转存 二Linux程序地址分析 一Core Dum ...
- html5新增表单元素
1.验证 <form> <input type="email"></input> 验证邮箱 <input type="ur ...
- 六、springboot集成Swagger2
1.Swagger简介 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法 ...
- JQuery怎么实现页面左侧菜单刷新后保留鼠标点击addclass的样式?
$('ul.main-menu li a').each(function(){ if($($(this))[0].href==String(window.location)) $(this).pare ...
- java基础67 JavaScript通过关系找节点、添加附件(网页知识)
1.通过关系找节点(父子关系,兄弟关系) 1.1.常用方法 parentNode:获取当前元素的父节点. childNodes:获取当前元素的所有下一级子元素 firstChild:获取当 ...
- No.3 selenium学习之路之鼠标&键盘事件
鼠标事件 from selenium.webdriver.common.action_chains import ActionChains contest_click() 右击 double_cli ...
- 再谈OPENCV(转)
转自:http://blog.csdn.net/carson2005/article/details/6979806 尽管之前写过一篇关于OpenCV的介绍(http://blog.csdn.net/ ...