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. 整体架构图 ...
随机推荐
- 使用httpClient调用接口,参数用map封装或者使用JSON参数,并转换返回结果
这里接口用表存起来,标记请求方式,然后接受参数,消息或者请求参数都可以, 然后先是遍历需要调用的接口,封装参数,再分别调用get与post即可,没有微服务还是得自己写 //消息转发-获取参数中对应参数 ...
- Dummynet模拟高时延网络场景(Windows7)
如果安装时出现:my_socket failed 2, cannot talk to kernel module 请查看是否以管理员方式运行,如果是,再判断当前操作系统是否为Win7 64位,如果是, ...
- Meltdown论文翻译【转】
转自:http://www.wowotech.net/basic_subject/meltdown.html#6596 摘要(Abstract) The security of computer sy ...
- replication-manager 搭建
replication-manager 搭建 介绍 replication-manager 主要用于mysql主从结构的监控和主从切换. 安装 vi /etc/yum.repos.d/signal18 ...
- 学习网站总结->
慕课大巴网:这是一个学习各类技术视频的网站 慕课大巴网点我-> 吾爱破解: 这是一个破解各类软件的网站 吾爱破解点我-> 鸠摩搜书:可以搜一些免费的书,我喜欢的都能搜到 鸠摩搜书点我-&g ...
- Python访问MySQL(1):初步使用PyMySQL包
Windows 10家庭中文版,MySQL 5.7.20 for Win 64,Python 3.6.4,PyMySQL 0.8.1,2018-05-08 ---- 使用Python访问MySQL数据 ...
- echarts 移动端地图数据可视化开发教程
如上效果图: 以下未代码: <!doctype html> <html lang="en"> <head> <meta charset ...
- 分析new delete 的本质
在程序设计中,数据可能会存在不同的内存空间,如函数栈 堆 全局变量区 ,今天我们来分析一下C++中堆分配方式和C语言的堆分配方式异同,从而更好的理解new delete本质 C语言使用mall ...
- 洛谷P1725 琪露诺
传送门啦 本人第一个单调队列优化 $ dp $,不鼓励鼓励? 琪露诺这个题,$ dp $ 还是挺好想的对不,但是暴力 $ dp $ 的话会 $ TLE $ ,所以我们考虑用单调队列优化. 原题中说她只 ...
- PHP实现菜单无限极分类
菜单数据 这里我们的菜单数据是临时数据, 没有从数据库中查询处理,数据基本和数据库中的的相似. 数据如下: $items = array( 1 => array('id' => 1, 'p ...