【发布时间】:2019-01-01 20:23:54
【问题描述】:
请指导我:有没有更有效的方法来执行这些任务:
- 将第一个制表符分隔文件中的键值对读取到映射容器中
- 从第二个制表符分隔文件(键值对)读取时,写入第三个文件
为 fname1 和 fname2 执行这两个步骤需要 3700 秒,共 7,000,000 行。
#include <string>
#include <map>
#include <fstream>
string col1;
int x;
map<string, int> m;
ifstream is1(fname1, ios::in | ios::binary);
ifstream is2(fname2, ios::in | ios::binary);
ofstream os3(fname3, ios::out | ios::binary);
if (is1.is_open())
{
while (is1 >> col1 >> x)
{
m[col1] = x;
}
is.close();
}
if (is2.is_open() && os3.is_open())
{
while (is2 >> col1 >> x)
{
if (m.count(col1) > 0)
x += m[col1];
os3 << col1 << "\t" << x << endl;
}
is2.close();
os3.close();
}
我做错了什么?有没有更有效的方法来执行这些任务? 还是文件 I/O 在大多数情况下是瓶颈?
更新:这里我放了相同算法的两个实现。主要问题:为什么 pythonic 版本的工作更快?我决定改用 C++,因为我听说它提供了更快的代码。我错了吗?
fname1, fname2 - 输入。 fname3 - 所需的输出。
fname1:
col1 col2 col3
1 1 1
2 2 2
fname2:
col1 col2 col3
1 1 2
3 3 3
fname3:
col1 col2 col3
1 1 3
2 2 2
3 3 3
def merge_two_files(fname1, fname2, fname3):
fout=open(fname3,'w')
fin1=open(fname1)
d1=dict()
for line in fin1:
l=line.strip().split('\t')
key='\t'.join(l[0:2])
d1[key] = float(l[2])
fin1.close()
d2=dict()
fin2=open(fname2)
for line in fin2:
l=line.strip().split('\t')
key='\t'.join(l[0:2])
d2[key] = float(l[2])
fin2.close()
for e in d1.viewkeys() & d2.viewkeys():
line_out='\t'.join([e,'{:.2f}'.format(d1[e]+d2[e])])
fout.write(line_out+'\n')
for e in d1.viewkeys() - (d1.viewkeys() & d2.viewkeys())
line_out='\t'.join([e,'{:.2f}'.format(d1[e])])
fout.write(line_out+'\n')
for e in d2.viewkeys() - (d1.viewkeys() & d2.viewkeys())
line_out='\t'.join([e,'{:.2f}'.format(d2[e])])
fout.write(line_out+'\n')
#include <fstream>
#include <string>
#include <unordered_map>
#include <set>
using namespace std;
int main() {
unordered_map < string, float > map1, map2 ;
set < string > s1, s2, both ;
string col1, col2, key, fname1, fname2, fname3 ;
float col3 ;
ifstream f1 ( fname1, ios::in | ios::binary) ;
ifstream f2 ( fname2, ios::in | ios::binary) ;
ofstream f3 ( fname3, ios::out | ios::binary) ;
if ( f1.is_open() ) {
while ( f1 >> col1 >> col2 >> col3 )
key= col1 + "\t" + col2 ;
map1.insert(make_pair(key,col3)) ;
s1.insert(key) ;
}
f1.close()
if ( f2.is_open() ) {
while ( f2 >> col1 >> col2 >> col3 ) {
key= col1 + "\t" + col2 ;
map2.insert(make_pair(key,col3)) ;
s2.insert(key) ;
}
}
f2.close() ;
set_intersection(s1.begin(), s1.end(),
s2.begin(), s2.end(),
inserter(both, both.begin())) ;
if ( f3.is_open() ) {
for ( const auto& e : both ) {
f3 << e << "\t" << map1.at(e) + map2.at(e) << "\n" ;
}
for ( const auto& kv : map1 ) {
if ( both.count(kv.first) ) continue ;
f3 << kv.first << "\t" << kv.second << "\n" ;
}
for ( const auto& kv : map2 ) {
if ( both.count(kv.first) ) continue ;
f3 << kv.first << "\t" << kv.second << "\n" ;
}
}
f3.close() ;
return 0;
}
【问题讨论】:
-
您使用的是优化版本吗?您是否有足够的 RAM 在不使用分页文件的情况下将所有内容保存在内存中?
-
将
endl替换为'\n'。endl每次都刷新文件,效率很低。 -
我已将
endl替换为'\n',但程序加速了一点,但还是谢谢你 - 我对流更熟悉了。 -
@1201ProgramAlarm、
-O3或-Ofast。我猜是。如何使用 PowerShell 检查:在操作系统开始使用分页文件之前有多少可用 RAM?