非理性繁荣

在python中使用threadpools

2月10日,2009。根据蟒蛇

像大多数程序员一样,我从在我的项目中使用线程中获得了秘密的乐趣。哦,我知道轻微的疏忽会导致僵局,这会破坏难以诊断的混乱,但让我们面对现实,线程是通往疯狂白日梦的通道,告诉你的新脚本如何有效地利用多个核心…或者利用它们,如果有人真的在使用它。

幸运的是,对于我们这些寻求被误导的高层的人,python使构建一个健全的线程池变得快速和容易。你只需要标准的库模块排队穿线..队列.queue是线程安全队列,和螺纹.螺纹提供用于创建线程的简单接口。

让我们来看一个在Python中安全使用线程的示例。

使用threadpool处理csv文件

这个脚本将遍历一个逗号分隔的值文件,并使用线程池来处理接收到的数据。

_未来__进口带语句时间进口睡觉猪瘟病毒进口听写器排队进口排队穿线进口螺纹Q=排队()工人=[]DEF工人()虽然线=Q.得到()打印“处理:%s\n%线Q.任务已完成()对于在里面范围):T=螺纹目标=工人T.设置守护进程工人.追加TT.开始()具有打开'myfile.csv'“R”作为对于线在里面听写器):Q.线Q.参加()

几点注意事项

  • 这是python2.5,你会想放弃从未来__为python2.6导入。对于3K,您将切换从队列导入队列从队列导入队列,以及将parens添加到打印.(我错过什么了吗?尚未实际使用PY3K…)

  • 我们正在使用csv.dictleader(听写器)而不是csv.阅读器因为它返回键=>值映射的字典(将第一行视为键)。与…相反csv.阅读器它返回一个有序的元组。

  • 您不必将线程保存在列表中(由工人以上)但这是一种简单的方法来保持对它们的引用。

  • 我用范围在这里,因为这是PY3K中的最后一个功能,但肯定会更适合使用润智对于py2.x代码。

我们可以通过使用登录中Optparse公司模块。

_未来__进口带语句进口登录中系统Optparse公司进口选项分析器时间进口睡觉猪瘟病毒进口听写器排队进口排队穿线进口螺纹DEF管理csv文件文件记录器螺纹=):Q=排队()工人=[]DEF工人()虽然线=Q.得到()尝试打印“处理:%s\n%线除了例外e记录器.错误“工作线程:%s%eQ.任务已完成()对于在里面范围螺纹):T=螺纹目标=工人T.设置守护进程工人.追加TT.开始()具有打开文件“R”作为对于线在里面听写器):Q.线Q.参加()DEF主要的()=选项分析器“用法:pool.py somefile.csv”.添加选项“T”'线程'='线程'帮助='要处理的线程数量'元变量='线程'选项阿尔茨海默病=.解析参数()文件名=阿尔茨海默病[]螺纹=int选项.螺纹如果选项.螺纹其他的日志级别=登录中.调试记录器=登录中.获取记录器“文件管理器”记录器.设置级别日志级别中国=登录中.流处理程序()中国.设置级别日志级别格式化程序=登录中.格式化程序%(asctime)秒-%(姓名)S-%(级别名称)s-%(消息)s中国.设置格式化程序格式化程序记录器.添加处理程序中国如果文件名.结束“CSV”):管理csv文件文件名记录器螺纹=螺纹其他的打印u“无法处理文件名%s%文件名.分裂'']如果_姓名__='主'系统.出口主要的()

在那里,您可以稍微调整一下,以满足您在分析数据之后做一些实际工作的需要。或者您可以扩展脚本来处理另一种格式…

添加对XML处理的支持

你可以把这篇文章的其余部分称为人为的,但我正在用新鲜的知识酿造元素树,所以让我们一起管理xml文件功能。

假设我们得到的XML文档是这种格式的…


         
         
         
         

…我们要处理每一个项目.但让我们把扳手扔进去。假设我们知道我们要处理根的孩子,但是我们甚至不知道根的名字,或者孩子的名字。而且,该死的,我们想快点做一次通过。让我们真的疯了:假设我们希望提取尽可能多的格式良好的元素,即使XML文档最终被证明是格式错误的。

首先,我们需要为elementtree添加导入。对于python 2.x,值得您花时间尝试导入芹菜如果有的话。

尝试XML.etree文件进口芹菜作为元素树除了导入错误XML.etree文件进口元素树

在python 3.0中,C和python模块之间的区别被大大消除了,所以这个试试……除了跳舞是不必要的,你只需要一个进口就可以逃脱。

XML.etree文件进口元素树

现在让我们把手弄脏。

DEF管理xml文件文件记录器螺纹=):DEF序列化e):'递归序列化elementTree.element'标签=e.标签文本=e.文本属性=e.项目()孩子们=e.儿童基金会()如果文本属性孩子们):返回文本其他的D={}如果文本D['文本']=文本对于钥匙瓦尔在里面属性D[钥匙]=瓦尔对于小孩在里面孩子们标签=小孩.标签序列化=序列化小孩如果D.有\键标签):瓦尔=D[标签]如果类型瓦尔=类型([]):瓦尔.追加序列化其他的D[标签]=[瓦尔序列化]其他的D[标签]=序列化返回DQ=排队()工人=[]DEF工人()虽然数据=Q.得到()尝试打印“处理:%s\n%数据除了例外e记录器.错误“工作线程:%s%eQ.任务已完成()对于在里面范围螺纹):T=螺纹目标=工人T.设置守护进程工人.追加TT.开始()项目标记=没有读者=伊特尔元素树.Iterparse公司文件事件='开始'“结束”))读者.下一个()#丢弃'
         
          '类型标记
         尝试对于事件ELEM在里面读者如果项目标记没有项目标记=ELEM.标签如果事件=“结束”ELEM.标签=项目标记Q.序列化ELEMELEM.清楚的()除了语法错误e记录器.批评的“遇到无效的XML,%s%eQ.参加()

关于这个脚本的一些注释:

  • 我发现将元素序列化为本地的Python字典并进行处理更为愉快。

    对,序列化函数有点冗长。是的,在一个足够嵌套的XML元素上,它会遇到Python对递归的限制。我同意。

    事实证明,将XML序列化为字典和数组的任何组合都是一种黑色艺术,但我认为序列化非常正确。

  • Iterparse公司很好地告诉我们它在哪一行和哪一个字符上失败了,这比许多XML库更慷慨,所以我们可以提取尽可能多的数据知道错误在哪里。不幸的是,要从XML中获得更多的信息将很难。

    Iterparse公司也是Python最快的XML处理器,这是它的其他方面的一个很好的副作用。

然后我们需要更新主要的检查文件是否以XML然后申请管理xml文件.

如果文件名.结束“CSV”):管理csv文件文件名记录器螺纹=螺纹否则如果文件名.结束“XML”):管理xml文件文件名记录器螺纹=螺纹其他的打印u“无法处理文件名%s%文件名.分裂'']

你可以看到GitHub上此脚本的更新版本.

我希望这个例子可以作为对Python线程工具的精彩世界的介绍。通过在这里和那里合并一些线程,可以从脚本和项目中挤出很多灵活性和效率。当然,你最终会被烧死的,但这意味着你是职业选手…

有点。

如果您有任何意见或投诉,请告诉我!


  1. 注意排队已重命名为队列在python 3.0中。还要注意,python 2.6附带了lifo的threadsafe实现,FIFO和优先级队列。幸运的混蛋。γ

  2. 你坐在那里想“这没用。没有人会这样做的。”上周末我把你养大了,我就是在那里…γ

  3. 我在尝试使用纯Python解决方案解析50兆JMdict时学到了这一课。花了很长时间。然后我换了进口,大概花了30秒。狗娘养的。γ