关于多线程操作。

对于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的更多相关文章

  1. Python168的学习笔记8

    #coding:utf8 #斐波那契数列,第三项起,每一项都等于前两项之和 def memo(func): cache = {}#闭包 def wrap(*args): if args not in ...

  2. Python168的学习笔记6

    如何派生内置不可变类型并修改实例化行为. 个人理解,如何派生出自己想要的类. class IntTuple(tuple): def __new__(cls,iterable): g = (x for ...

  3. Python168的学习笔记5

    关于对csv文件的操作. python标准库中有csv的库,使用非常方便. import csv with open('pingan.csv','rb') as rf: reader = csv.re ...

  4. Python168的学习笔记4

    关于普通文本文件的读写 python2.7中,未注明的字符都是以acsii来编码的,而要让字符能够通用,必须声明为unicode. s=u'你好',s.encode('utf8')就是指用utf8来进 ...

  5. Python168的学习笔记3

    list.extend(),可以拓展list,a=(0,1),b=(2,3) a.extend(b),a就变成(0,1,2,3) 分割字符串(除去字符串中的,\/;之类的),如果用str.split( ...

  6. Python168的学习笔记2

    关于for循环,其实质是利用被循环对象的__iter__,或者__getitem__属性接口,由可迭代对象得到迭代器.for循环就是不断调用.next(),直到最终捕获到stop. import re ...

  7. Python168的学习笔记1

    在对list的条件选择有两种常用方法,直接使用filter函数,就是filter(func,sequence);另外一种就是迭代操作,类似 x for x in sequence func.这两种方法 ...

  8. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  9. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

随机推荐

  1. vue中使用cookie记住用户上次选择(本次例子中为下拉框)

    最近工作中碰到一个需求,添加一条数据时,自动记住上次选择的下拉框的数据,刚开始觉得没思路,后来请教了项目组长,组长直接一句,这不很简单吧,直接用cookie,我:....... 好吧,都王的差不多了, ...

  2. XSS注入常用语句

    <script>alert('hello,gaga!');</script> //经典语句,哈哈! >"'><img src="javas ...

  3. 乐视mysql面试题【转】

    最近,朋友去乐视面试了mysql DBA,以下是我据整理的乐视mysql面试题答案,供大家参考 1. MYISAM和INNODB的不同?答:主要有以下几点区别:   a)构造上的区别     MyIS ...

  4. ARKit从入门到精通

    ARKit从入门到精通(10)-ARKit让飞机绕着你飞起来 ARKit从入门到精通(9)-ARKit让飞机跟着镜头飞起来 ARKit从入门到精通(8)-ARKit捕捉平地 ARKit从入门到精通(7 ...

  5. 使用PyMongo访问需要认证的MongoDB

    Windows 10家庭中文版,Python 3.6.4,PyMongo 3.7.0,MongoDB 3.6.3,Scrapy 1.5.0, 前言 在Python中,使用PyMongo访问Mongod ...

  6. python基础-各模块文章导航

    python基础学习日志day5-各模块文章导航 python基础学习日志day5---模块使用 http://www.cnblogs.com/lixiang1013/p/6832475.html p ...

  7. 在VirtualBox虚拟机中安装Centos操作系统怎么与本地XShell远程连接

    问题: 在VirtualBox安装好了CentOS操作系统后,我们怎么才可以用XSell连接虚拟机中的CentOS呢? 答案: (1)在windows下用cmd--ipconfig查看VirtualB ...

  8. css 让背景图片不停旋转

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. (转载)solr实现满足指定距离范围条件的搜索

    配置schema.xml <?xml version="1.0" encoding="UTF-8" ?> <schema name=" ...

  10. scrapy 设置cookie池

    代码已经很详细了,可以直接拿来使用了. 包含了: 从网页获取cookie 存入mongodb 定期删除cookie scrapy中间件对cookie池的取用 #!/usr/bin/python #co ...