我必须从网络服务器的htdocs目录中获取大量文件名,然后使用此文件名列表搜索大量存档日志文件,以便最后访问这些文件。
我打算用Boost在C ++中做这个。我会先获取最新的日志然后向后读它,检查我得到的所有文件名的每一行。
如果文件名匹配,我从Logstring读取Time并保存它的最后一次访问。现在我不再需要查找此文件,因为我只想知道上次访问。
要搜索的文件名向量应该快速减少。
我想知道如何处理这种多线程最有效的问题。
我是否对日志文件进行分区,让每个线程从内存中搜索一部分日志,如果一个线程匹配,它会从文件名向量中删除该文件名,还是有更有效的方法来执行此操作?
答案 0 :(得分:1)
将日志文件解析为数据库表(SQLite ftw)。其中一个领域就是路径。
在另一个表格中,添加您要查找的文件。
现在它是派生表上的简单连接。这样的事情。
SELECT l.file, l.last_access FROM toFind f
LEFT JOIN (
SELECT file, max(last_access) as last_access from logs group by file
) as l ON f.file = l.file
toFind中的所有文件都在那里,并且对于那些在日志中找不到的文件,它们的last_access为NULL。
答案 1 :(得分:1)
尝试使用mmap,它会为您节省相当多的脱发。我感觉很快,并且有些奇怪的心情回忆起我的mmap知识,所以我写了一个简单的事情让你开始。希望这有帮助!
mmap的优点在于它可以轻松地与OpenMP并行化。这也是防止I / O瓶颈的一种非常好的方法。让我首先定义Logfile类,然后我将继续实现。
这是头文件(logfile.h)
#ifndef _LOGFILE_H_
#define _LOGFILE_H_
#include <iostream>
#include <fcntl.h>
#include <stdio.h>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using std::string;
class Logfile {
public:
Logfile(string title);
char* open();
unsigned int get_size() const;
string get_name() const;
bool close();
private:
string name;
char* start;
unsigned int size;
int file_descriptor;
};
#endif
这是.cpp文件。
#include <iostream>
#include "logfile.h"
using namespace std;
Logfile::Logfile(string name){
this->name = name;
start = NULL;
size = 0;
file_descriptor = -1;
}
char* Logfile::open(){
// get file size
struct stat st;
stat(title.c_str(), &st);
size = st.st_size;
// get file descriptor
file_descriptor = open(title.c_str(), O_RDONLY);
if(file_descriptor < 0){
cerr << "Error obtaining file descriptor for: " << title.c_str() << endl;
return NULL;
}
// memory map part
start = (char*) mmap(NULL, size, PROT_READ, MAP_SHARED, file_descriptor, 0);
if(start == NULL){
cerr << "Error memory-mapping the file\n";
close(file_descriptor);
return NULL;
}
return start;
}
unsigned int Logfile::get_size() const {
return size;
}
string Logfile::get_title() const {
return title;
}
bool Logfile::close(){
if( start == NULL){
cerr << "Error closing file. Was closetext() called without a matching opentext() ?\n";
return false;
}
// unmap memory and close file
bool ret = munmap(start, size) != -1 && close(file_descriptor) != -1;
start = NULL;
return ret;
}
现在,使用此代码,您可以使用OpenMP来共享这些日志文件的解析,即
Logfile lf ("yourfile");
char * log = lf.open();
int size = (int) lf.get_size();
#pragma omp parallel shared(log, size) private(i)
{
#pragma omp for
for (i = 0 ; i < size ; i++) {
// do your routine
}
#pragma omp critical
// some methods that combine the thread results
}
答案 2 :(得分:0)
好的,这已经是几天前了,但我花了一些时间编写代码并在其他项目中使用SQLite。
我仍然希望将DB-Approach与MMAP解决方案进行比较,仅仅是为了性能方面。
当然,如果您可以使用SQL-Queries来处理您解析的所有数据,它可以为您节省大量的工作。但我真的不关心工作量,因为我还在学习很多东西,我从中学到的是:
这种MMAP方法 - 如果你正确实施 - 在性能上绝对优越。令人难以置信的快速,你会注意到你实现了“字数统计”的例子,它可以被视为MapReduce算法的“你好世界”。
现在,如果您还想从SQL语言中受益,那么正确的方法就是实现您自己的SQL-Wrapper,它通过在线程之间共享查询来使用Map-Reduce。
您可以在线程之间按ID共享对象,其中每个线程都处理它自己的DB-Connection。然后它会查询对象中自己的数据集部分。
这比用通常的方式写SQLite DB要快得多。
毕竟你可以说:
MMAP是处理字符串处理的最快方法 SQL为解析器应用程序提供了很好的功能,但是如果你没有实现一个用于处理SQL-Queries的包装器,它就会减慢速度