gpt4 book ai didi

c# - 如何使用 C# mongo 驱动程序达到与 python 中的 PyMongo 相同的性能?

转载 作者:太空狗 更新时间:2023-10-30 00:58:13 27 4
gpt4 key购买 nike

在当前关于 mongodb 驱动程序的基准测试中,我们注意到 python 和 .Net(核心或框架)之间的性能存在巨大差异。

在我看来,部分差异可以用这个来解释。

我们得到了以下结果:


┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┓
┃ Metric ┃ Csharp ┃ Python ┃ ratio p/c ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━┫
┃ Ratio Duration/Document ┃ 24.82 ┃ 0.03 ┃ 0.001 ┃
┃ Duration (ms) ┃ 49 638 ┃ 20 016 ┃ 0.40 ┃
┃ Count ┃ 2000 ┃ 671 972 ┃ 336 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━┛

我们查看了 C# 中的内存分配,发现 BsonChunck 的下载阶段和反序列化之间存在乒乓效应。 (正常,因为它是按批处理的。)但是下载阶段很长。所以我们查看了不同查询的网络跟踪,因为 mongo 使用 TCP/IP:

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Metric ┃ Csharp ┃ Python ┃ ratio p/c ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━┫
┃ Packets/sec to db ┃ 30 ┃ 160 ┃ 5.3 ┃
┃ Packets/sec from DB ┃ 120 - 150 ┃ 750 - 1050 ┃ ~6.5 ┃
┃ Packet count to db ┃ 1560 ┃ 2870 ┃ 1.84 ┃
┃ Packet count from db ┃ 7935 ┃ 13663 ┃ 1.7 ┃
┃ Packet average length to db ┃ 73.6 ┃ 57.6 ┃ 0.74 ┃
┃ Packet average length from db ┃ 1494 ┃ 1513 ┃ 1.01 ┃
┃ Max TCP Errors/sec ┃ 20 ┃ 170 ┃ 8.5 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━┛

对于配置文件,只有以下配置文件的结果是惊人的:

{
"connectionString": "mongodb://ip.of.the.mongo:27018",
"dbname" : "mydb",
"colname" : "mycollection",
"query" : {},
"projection" :{},
"limit" : 2000,
"batchsize": 10
}

一个对象的延迟令人印象深刻:python 为 0.03 毫秒,csharp 为 24.82 毫秒。

您对这种差异有一些见解吗?您知道在 C# 中达到与在 Python 中相同性能的方法吗?提前谢谢你:-)

为了做基准测试,我们使用这两个代码:

Python(pymongo 驱动程序):

#!/usr/bin/env python3

import pymongo
import time
import json
import os

queries_dir = "../queries"
results_dir = "../results"

for subdir, dirs, files in os.walk(queries_dir):
for f in files:
filepath = subdir + os.sep + f
print(filepath)
conf = json.load(open(filepath))
conf["language"] = "python"
client = pymongo.MongoClient(conf["connectionString"])
db = client[conf["dbname"]]
col = db[conf["colname"]]

initConnection = col.find({}, {}).limit(1)
for element in initConnection:
print(element)

input("Press enter to continue.")

res = col.find(conf["query"], conf["projection"])
returned = 0

start = time.time()
for i in res:
returned += 1
duration = (time.time() - start) * 1000
conf["duration"] = duration
conf["returned"] = returned
conf["duration_per_returned"] = float(duration) / float(returned)
d = time.strftime("%Y-%m-%d_%H-%M-%S")
fr = open(results_dir + os.sep + d + "_" + conf["language"] + "_" + f,"w")
json.dump(conf, fr, indent=4, sort_keys=True)
fr.close()
print(json.dumps(conf,indent=4, sort_keys=True))

对于 .Net (MongoDB.Driver):

class Program
{
static void Main(string[] args)
{
var dir = Directory.GetCurrentDirectory();
var queryDirectory = dir.Replace(@"csharp\benchmark\benchmark\bin\Debug\netcoreapp2.2", string.Empty) + "queries";
var resultDirectory = dir.Replace(@"csharp\benchmark\benchmark\bin\Debug\netcoreapp2.2", string.Empty)+ "results";
var configurationFiles = Directory.GetFiles(queryDirectory);
foreach (var file in configurationFiles)
{
var configuration = JsonConvert.DeserializeObject<BenchmarkConfiguration>(File.ReadAllText(file));
var collection = new MongoClient(configuration.ConnectionString)
.GetDatabase(configuration.Database)
.GetCollection<BsonDocument>(configuration.Collection);
var filters = BsonDocument.Parse((string)(configuration.Query.ToString()));
var projection = BsonDocument.Parse((string)(configuration.Projection.ToString()));
var query = collection.Find(filters, new FindOptions { BatchSize = configuration.BatchSize }).Project(projection).Limit(configuration.Limit);

var initconnection = collection.Find(new BsonDocument { }).Limit(1).FirstOrDefault();
Console.WriteLine(initconnection.ToString());
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();

var watch = new Stopwatch();
watch.Start();
var results = query.ToList();
watch.Stop();
var time = watch.ElapsedMilliseconds;
var now = DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss");
var report = new BenchmarkResult(configuration, time, results.Count());
File.WriteAllText($"{resultDirectory}/{now}_csharp_{Path.GetFileName(file)}", JsonConvert.SerializeObject(report, Formatting.Indented));
}
}
}

旧指标:在从基准循环中删除连接拉动之前。


┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┓
┃ Metric ┃ Csharp ┃ Python ┃ ratio p/c ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━┫
┃ Ratio Duration/Document ┃ 26.07 ┃ 0.06 ┃ 0.002 ┃
┃ Duration (ms) ┃ 52 145.0 ┃ 41 981 ┃ 0.80 ┃
┃ Count ┃ 2000 ┃ 671 972 ┃ 336 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Metric ┃ Csharp ┃ Python ┃ ratio p/c ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━┫
┃ Packets/sec to db ┃ 30 ┃ 150 ┃ 5 ┃
┃ Packets/sec from DB ┃ 120 - 180 ┃ 750 - 1050 ┃ ~6 ┃
┃ Packet count to db ┃ 1540 ┃ 2815 ┃ 1.8 ┃
┃ Packet count from db ┃ 7946 ┃ 13700 ┃ 1.7 ┃
┃ Packet average length to db ┃ 74 ┃ 59 ┃ 0.80 ┃
┃ Packet average length from db ┃ 1493 ┃ 1512 ┃ 1 ┃
┃ Max TCP Errors/sec ┃ 10 ┃ 320 ┃ 32 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━┛

最佳答案

pymongo 的投影问题

您正在试验的 C# 和 python 驱动程序之间的性能差异是由于 python pymongo lib 如何理解空 { } 投影中的一个非常小的细节造成的。

在 mongodb-shell 和 C# 驱动程序中,{ } 投影会返回整个文档。实际上根本没有投影。它可能被视为默认行为,因为 mongodb-shell 就是这样。

但是,使用 pymongo 的 python 中的 { } 投影只返回 _id 字段!
文档越多,您的 C# 代码下载文档所需的时间就越多,而您的 Python 代码只需要非常小的 _id。

修复你的代码

如果你从

res = col.find(conf["query"], conf["projection"]) #projection being { }.
for i in res:
print(i) # Only print Id fields.
returned += 1

res = col.find(conf["query"])
for i in res:
print(i) # Whole document 'downloaded' and printed.
returned += 1

您会注意到两者都表现良好。

关于c# - 如何使用 C# mongo 驱动程序达到与 python 中的 PyMongo 相同的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57621853/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com