Python 处理文件的性能优化

2014-08-03 23:00:47 +08:00
 wwttc
现在有一个list包含有1500个topic,另外一个文件包含一亿个微博数据,现在我想统计,1500个topic中每个topic分别有多少条微博包含它们,我写的代码如下,但是运行起来需要非常久的时间,有什么办法可以优化吗?

f = file("largefile.txt")
for line in f:
try:
tweet_time = line.split(',',3)[2].split()[0]
tweet = line.split(',',3)[-1]
for topic in topics:
topic_items = topic.split()
isContain = True
for item in topic_items:
if item not in tweet:
isContain = False
break
if isContain:
pass
except:
continue
f.close()
8752 次点击
所在节点    问与答
44 条回复
paulw54jrn
2014-08-03 23:20:31 +08:00
知乎的面试题..?
czheo
2014-08-03 23:29:03 +08:00
把topics存set里面,再用in
eriale
2014-08-03 23:50:04 +08:00
@czheo python的set做iteration比list慢啊。
这么大的数量,而且彼此之间没有相关性,用并行方式来做有很好的通用性。
leiz
2014-08-04 00:40:28 +08:00
猜测: topics = [topic0, topic1, ... topicn],topic = 'aaa bbb ccc ... zzz'
几个点:
1. 慢主要是文件读取?
2. topics本身还是比较复杂,是不是再预处理一下会比较好?
3. 为什么要把tweet再次打散才进行比较?直接用类似string.contain之类的方法是否可以?
4. 这种对比和统计,是不是可以用dict来做会比较快?
rrfeng
2014-08-04 09:11:01 +08:00
1. topic 放 set,线性查找
2. topics 分片,并行处理

其实 in set(1500)的话几乎没什么时间开销,就是 IO 的速度了,所以分片不见得有什么好的效果
sujin190
2014-08-04 09:23:52 +08:00
@eriale python的set底层是用hash表实现的,怎么会比list慢呢?
dingyaguang117
2014-08-04 09:44:24 +08:00
感觉是CPU瓶颈,不知道Python字符串比较效率如何
wwttc
2014-08-04 09:44:47 +08:00
@eriale 已经实现过Hadoop版本了,现在需要跑单机的版本
clino
2014-08-04 09:52:35 +08:00
我觉得搜索一条微博有没有包含"1500个topic"之一是不是转成正则表达式来匹配会更快一些?
觉得搜索1500次应该很慢

另外读文件如果能一次读多行(如1000行),减少IO操作的次数会不会快一些

另外如果能利用到多核的话肯定会更好一些,所以可以看有几核,就起几个进程分别做肯定能更快的
wwttc
2014-08-04 09:58:59 +08:00
@leiz
1.topic大部分是一个中文单词,有一部分是几个单词的组合,比如说:“爸爸去哪儿 多多”。
2.没有把tweet打散啊。还是一条一条的比较。试过string的方法,速度好像更慢。
3.嗯,dict查找应该会比list快点。但是这里仅仅是使用了in操作,你的意思是说,把每个tweet都拆分存到dict里面?
wwttc
2014-08-04 10:06:09 +08:00
@clino
1.用正则速度应该会更慢。
2.嗯,有道理。原来文件小的时候,用readlines一次全部读完,速度会快点。我试试分块的效率怎么样
captainhcg
2014-08-04 10:10:18 +08:00
这个排版有问题,看不到缩进。建议你把所有缩进的空格都换成"."

如果我没猜错你用了三层for循环,100,000,000 * 1500 * n(n是啥我还没看懂)。至少在我的工作里极少用到>=3的for循环,用到了基本就是代码写得有问题了。

你把代码重排个版我再看看
clino
2014-08-04 10:11:45 +08:00
@wwttc 你可以试试,只要每次使用正则预编译好的对象,我猜测会比循环搜索更快
因为正则预编译以后,有点相当于搜索的规则给索引了
takato
2014-08-04 10:26:34 +08:00
如果这是一道题目,考的一定是算法。。。

你大概需要一个高级数据结构来支撑这个需求。各种空间换时间。

绝非暴力能过的。。
wwttc
2014-08-04 10:29:38 +08:00
f = file("largefile")
....for line in f:
........try:
............tweet_time = line.split(',',3)[2].split()[0] # 微博发布时间
............tweet = line.split(',',3)[-1] # 微博内容
............for topic in topics:
................topic_items = topic.split() # 每个topic可能有多个词组成
................isContain = True
................for item in topic_items:
....................if item not in tweet:
........................isContain = False
........................break
....................if isContain:
........................pass # 该微博包含该topic
........except:
............continue
f.close()
imn1
2014-08-04 10:40:06 +08:00
首先,topic是固定的,没理由在循环内每次拆解,移到循环外面
这种多对多简单in比较,我会考虑用pandas或者sql
yangqi
2014-08-04 10:49:38 +08:00
这么简单的查找为什么不直接用grep...
captainhcg
2014-08-04 11:04:15 +08:00
你先看看这样行不行。可能有语法错误,没测试
with file("largefile") as f:
....topic_items_list = [t.split() for t in topics] # 每个topic可能有多个词组成
....for line in f:
........tweet_time = line.split(',',3)[2].split()[0] # 微博发布时间
........tweet = line.split(',',3)[-1] # 微博内容
........for topic_items in topic_items_list:
............if all(item in tweet for item in topic_items):
................pass # do sth
wwttc
2014-08-04 11:05:42 +08:00
@captainhcg
我最早也是用all函数,测试了下发现速度要比现在的慢。
wwttc
2014-08-04 11:06:37 +08:00
@yangqi
grep是快多了,但是我这边由于某种原因要求是用Python来做

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/125941

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX