
はてなキーワード:mmapとは
utf8の文字コードで構成されたバイナリーファイルがある。このファイルの改行の数を数えよ。改行はCRのみとする。このファイルにはCR が必ず含まれており、CRで分割すればマルチスレッドで処理できる。
size_t count_cr_in_file(conststd::string&path) {
std::ifstreamfs(path,std::ios::binary);
size_t size =fs.tellg();
fs.seekg(0);
const size_tthread_count =std::thread::hardware_concurrency();
const size_t chunk_size = size /thread_count;
std::vector<std::future<size_t>> futures;
for (size_t t = 0; t <thread_count; t++) {
size_t start = t * chunk_size;
size_t end = (t ==thread_count - 1 ? size : (t + 1) * chunk_size);
futures.push_back(std::async(std::launch::async, [start, end, &path]() {
std::ifstreamfs(path,std::ios::binary);
fs.seekg(start);
size_t count = 0;
for (size_t i = start; i < end; i++) {
char c;
if (c == '\r') count++;
}
return count;
}));
}
size_ttotal = 0;
for (auto& f : futures)total += f.get();
returntotal;
}
importmmap
mm =mmap.mmap(f.fileno(), 0,access=mmap.ACCESS_READ)
returnmm.count(b'\r')
c#で書けと指示したところ、
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
{
public static long CountCRInFile(stringpath)
{
using varmmf = MemoryMappedFile.CreateFromFile(path, FileMode.Open, null);
using varaccessor =mmf.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);
long fileSize =accessor.Capacity;
int processorCount = Environment.ProcessorCount;
long chunkSize = fileSize / processorCount;
longtotal = 0;
Parallel.For(0, processorCount, i =>
{
long start = i * chunkSize;
long end = (i == processorCount - 1) ? fileSize : (i + 1) * chunkSize;
long localCount = 0;
byte b;
for (longpos = start;pos < end;pos++)
{
if (b == 0x0D) //CR
localCount++;
}
lock (lockObj)
{
total += localCount;
}
});
returntotal;
}
{
long count = CountCRInFile(path);
Console.WriteLine($"CR count = {count}");
}
}
というコードが出てきた。
実際はcrlf,lfもあり得るんだが、そこは考慮しなくてもよく、そう考えるとaiはすごいとしか言いようがない。
なお、utf8として成立する単位で区切りつつ改行を数える場合、もう一工夫いる。
僕はプログラミング歴2週間の初心者です。キーと値を入力できるデータベースを作っています。
以下のコードを実行してデータを追加し続けると、一定のサイズを超えるとエラーが出てしまうみたいです。
理想は、データが追加された後にサイズが足りなくなったら動的に自動拡大されることです。
もし詳しい人がいたらご教示お願い致します。
import sysimportosimportmmapimport hashlibdef h(x): return int(hashlib.sha512(x.encode()).hexdigest(), 16)def create_db(filename): withopen(filename, 'wb')as f: f.write(b'\0' * 1024 * 1024) # 1MBの空ファイルを作成defset_key(filename,key,value): withopen(filename, 'r+b')as f:mm =mmap.mmap(f.fileno(), 0)pos = h(key) %mm.size() whilemm[pos:pos+1] != b'\0':pos = (pos + 1) %mm.size() ifpos == h(key) %mm.size():f.seek(0,os.SEEK_END) f.write(b'\0' *mm.size()) #ファイルサイズを2倍にするmm =mmap.mmap(f.fileno(), f.tell()) #ファイルサイズを反映させるpos = h(key) %mm.size() #ハッシュ値を再計算する data =key + '\0' +value + '\0' data = data.encode()mm[pos:pos+len(data)] = datamm.close() #mmapオブジェクトを閉じるdefget_key(filename,key): withopen(filename, 'r+b')as f:mm =mmap.mmap(f.fileno(), 0)pos = h(key) %mm.size() whilemm[pos:pos+1] != b'\0': end =mm.find(b'\0',pos,mm.size()) # 第2引数と第3引数を指定する if end == -1: end =mm.size() ifmm[pos:end].decode() ==key:pos = end + 1 end =mm.find(b'\0',pos,mm.size()) # 第2引数と第3引数を指定する if end == -1: end =mm.size()value =mm[pos:end].decode()mm.close() #mmapオブジェクトを閉じる returnvaluepos = (pos + 1) %mm.size() ifpos == h(key) %mm.size(): breakmm.close() #mmapオブジェクトを閉じる return Nonedefmain(): cmd = sys.argv[1] if cmd == 'create': create_db(sys.argv[2]) elif cmd == 'set':set_key(sys.argv[2], sys.argv[3], sys.argv[4]) elif cmd == 'get':print(get_key(sys.argv[2], sys.argv[3]))if __name__ == '__main__':main()