为什么我的 D 代码没有达到预期的性能?
Why my D code is not performant as expected?
我做一个基准测试是为了自己的乐趣!我用多种编程语言编写了一部分代码,并使用 ab 对其进行基准测试,以查看哪个更快以及多少。我知道该方法可能不是那么有效,不能作为使用某些方法的证据,但为了我自己的信息,我正在这样做。我想知道的另一个因素是 easy/difficult 如何用每种语言编写相同的样本。我在 Python/Python(asyncio)、Haskell、Go、Kotlin 和 D 中编写了代码。我期望 D 端口比 Go 更快(或者至少速度相等)。但不幸的是我的 D 代码比 Go 慢得多。在这里我放了其他代码,请帮助我为什么代码没有预期的那么快。还是我的期望完全错了?
import cbor;
import std.array : appender;
import std.format;
import std.json;
import vibe.vibe;
struct Location
{
float latitude;
float longitude;
float altitude;
float bearing;
}
RedisClient redis;
void main()
{
auto settings = new HTTPServerSettings;
redis = connectRedis("localhost", 6379);
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, &hello);
logInfo("Please open http://127.0.0.1:8080/ in your browser.");
runApplication();
}
void hello(HTTPServerRequest req, HTTPServerResponse res)
{
if (req.path == "/locations") {
immutable auto data = req.json;
immutable auto loc = deserializeJson!Location(data);
auto buffer = appender!(ubyte[])();
encodeCborAggregate!(Flag!"WithFieldName".yes)(buffer, loc);
auto db = redis.getDatabase(0);
db.set("Vehicle", cast(string) buffer.data);
res.writeBody("Ok");
}
}
这是围棋
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
)
import "github.com/go-redis/redis"
import (
"bytes"
"github.com/2tvenom/cbor"
)
type Location struct {
Latitude float32 `json:"latitude"`
Longitude float32 `json:"longitude"`
Altitude float32 `json:"altitude"`
Bearing float32 `json:"bearing"`
}
func main() {
app := iris.New()
client := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
app.Post("/locations", func(ctx context.Context) {
var loc Location
ctx.ReadJSON(&loc)
var buffTest bytes.Buffer
encoder := cbor.NewEncoder(&buffTest)
encoder.Marshal(loc)
client.Set("vehicle", buffTest.Bytes(), 0)
client.Close()
ctx.Writef("ok")
})
app.Run(iris.Addr(":8080"), iris.WithCharset("UTF-8"))
}
使用 ab,Go 的结果约为 4200 req/sec,而 D 约为 2800 req/sec!
您不仅要对 Go 与 D 进行基准测试。您还要对非标准 Go 和 D 库的特定选择进行相互基准测试:cbor
、vibe
、iris
,等等。您正在对您的特定实现进行基准测试 which can easily vary by 1000x in performance。
有了这么多变量,原始基准测试数据对于比较两种语言的性能来说毫无意义。这些第 3 方库中的任何一个都可能导致性能问题。实际上,您只是在比较这两个特定程序。这是尝试跨语言比较除琐碎程序之外的任何东西的核心问题:变量太多。
您可以通过 performance profiling 减少其中一些变量的影响;在 Go 中,这将是 go tool pprof
。这将告诉您哪些函数和行被调用了多少次以及占用了多少资源。有了它,您可以找到瓶颈,代码中消耗大量资源的地方,并将优化工作集中在那里。
当您为每个版本进行配置文件和优化轮次时,您将更接近于比较真实的、优化的实现。或者,您将更好地了解每种语言和库有效地做什么,不有效地做什么。
比较语言的问题在很大程度上受特定问题和特定程序员的影响。 X 程序员总是发现 X 是最好的语言,不是因为 X 是最好的语言,而是因为 X 程序员在用 X 编写时是他们最好的,并且可能选择了他们熟悉的问题。正因为如此,有许多项目可以为每种语言提供最佳实现。
第一个想到的是The Computer Language Benchmarks Game。他们会围棋,但不会围棋。也许你可以添加它?
我做一个基准测试是为了自己的乐趣!我用多种编程语言编写了一部分代码,并使用 ab 对其进行基准测试,以查看哪个更快以及多少。我知道该方法可能不是那么有效,不能作为使用某些方法的证据,但为了我自己的信息,我正在这样做。我想知道的另一个因素是 easy/difficult 如何用每种语言编写相同的样本。我在 Python/Python(asyncio)、Haskell、Go、Kotlin 和 D 中编写了代码。我期望 D 端口比 Go 更快(或者至少速度相等)。但不幸的是我的 D 代码比 Go 慢得多。在这里我放了其他代码,请帮助我为什么代码没有预期的那么快。还是我的期望完全错了?
import cbor;
import std.array : appender;
import std.format;
import std.json;
import vibe.vibe;
struct Location
{
float latitude;
float longitude;
float altitude;
float bearing;
}
RedisClient redis;
void main()
{
auto settings = new HTTPServerSettings;
redis = connectRedis("localhost", 6379);
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, &hello);
logInfo("Please open http://127.0.0.1:8080/ in your browser.");
runApplication();
}
void hello(HTTPServerRequest req, HTTPServerResponse res)
{
if (req.path == "/locations") {
immutable auto data = req.json;
immutable auto loc = deserializeJson!Location(data);
auto buffer = appender!(ubyte[])();
encodeCborAggregate!(Flag!"WithFieldName".yes)(buffer, loc);
auto db = redis.getDatabase(0);
db.set("Vehicle", cast(string) buffer.data);
res.writeBody("Ok");
}
}
这是围棋
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
)
import "github.com/go-redis/redis"
import (
"bytes"
"github.com/2tvenom/cbor"
)
type Location struct {
Latitude float32 `json:"latitude"`
Longitude float32 `json:"longitude"`
Altitude float32 `json:"altitude"`
Bearing float32 `json:"bearing"`
}
func main() {
app := iris.New()
client := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
app.Post("/locations", func(ctx context.Context) {
var loc Location
ctx.ReadJSON(&loc)
var buffTest bytes.Buffer
encoder := cbor.NewEncoder(&buffTest)
encoder.Marshal(loc)
client.Set("vehicle", buffTest.Bytes(), 0)
client.Close()
ctx.Writef("ok")
})
app.Run(iris.Addr(":8080"), iris.WithCharset("UTF-8"))
}
使用 ab,Go 的结果约为 4200 req/sec,而 D 约为 2800 req/sec!
您不仅要对 Go 与 D 进行基准测试。您还要对非标准 Go 和 D 库的特定选择进行相互基准测试:cbor
、vibe
、iris
,等等。您正在对您的特定实现进行基准测试 which can easily vary by 1000x in performance。
有了这么多变量,原始基准测试数据对于比较两种语言的性能来说毫无意义。这些第 3 方库中的任何一个都可能导致性能问题。实际上,您只是在比较这两个特定程序。这是尝试跨语言比较除琐碎程序之外的任何东西的核心问题:变量太多。
您可以通过 performance profiling 减少其中一些变量的影响;在 Go 中,这将是 go tool pprof
。这将告诉您哪些函数和行被调用了多少次以及占用了多少资源。有了它,您可以找到瓶颈,代码中消耗大量资源的地方,并将优化工作集中在那里。
当您为每个版本进行配置文件和优化轮次时,您将更接近于比较真实的、优化的实现。或者,您将更好地了解每种语言和库有效地做什么,不有效地做什么。
比较语言的问题在很大程度上受特定问题和特定程序员的影响。 X 程序员总是发现 X 是最好的语言,不是因为 X 是最好的语言,而是因为 X 程序员在用 X 编写时是他们最好的,并且可能选择了他们熟悉的问题。正因为如此,有许多项目可以为每种语言提供最佳实现。
第一个想到的是The Computer Language Benchmarks Game。他们会围棋,但不会围棋。也许你可以添加它?