gpt4 book ai didi

performance - 如何提高Dart进行二进制数据转换的性能?

转载 作者:行者123 更新时间:2023-12-03 13:33:25 26 4
gpt4 key购买 nike

为更大的德国公司Future Technology Group做一些咨询工作。我已经向Dart移植了大约6000行Java服务器端软件。这应该有助于回答Dart是否可以在服务器上有效使用的问题。 (由于寻求为客户端和服务器端编程使用一种语言的优势,Dart本身将为Dart开绿灯。)

了解Dart(我非常喜欢与之合作)使我期望相对于Java而言性能下降30%至50%,但无论如何都不会低于100%(慢两倍),这是上述决策过程的起点以上。

港口进展顺利。我学到了很多。单元测试很好。但是结果却是非常糟糕的……与Java程序相比,整体速度要慢七倍。

对代码进行性能分析揭示了两个主要的根源:数据转换和文件I / O。也许我做错了什么?在我返回客户之前,他们取消了对Dart的研究,我想搜索一些有关如何改进功能的建议。让我们从数据转换开始,将原始Dart数据类型转换为各种二进制格式,这些格式可用于有效地传输和存储数据。

通常,这些转换是简单且非常快速的,因为实际上不需要从使用的内部格式转换任何内容,而是将大多数内容存储到缓冲区中。我创建了一个基准程序,该程序以某种方式反射(reflect)了程序中这些转换的典型用法:

import 'dart:typed_data';
import 'package:benchmark_harness/benchmark_harness.dart';

// Create a new benchmark by extending BenchmarkBase
class ConversionBenchmark extends BenchmarkBase {

Uint8List result;

ConversionBenchmark() : super("Conversion");

// The benchmark code.
void run() {
const int BufSize = 262144; // 256kBytes
const int SetSize = 64; // one "typical" set of data, gets repeated
ByteData buffer = new ByteData(BufSize);
double doubleContent = 0.0; // used to simulate double content
int intContent = 0; // used to simulate int content
int offset = 0;
for (int j = 0; j < buffer.lengthInBytes / SetSize; j++) {
// The following represents some "typical" conversion mix:
buffer.setFloat64(offset, doubleContent); offset += 8; doubleContent += 0.123;
for (int k = 0; k < 8; k++) { // main use case
buffer.setFloat32(offset, doubleContent); offset += 4; doubleContent += 0.123;
}
buffer.setInt32(offset, intContent); offset += 4; intContent++;
buffer.setInt32(offset, intContent); offset += 4; intContent++;
buffer.setInt16(offset, intContent); offset += 2; intContent++;
buffer.setInt16(offset, intContent); offset += 2; intContent++;
buffer.setInt8(offset, intContent); offset += 1; intContent++;
buffer.setInt8(offset, intContent); offset += 1; intContent++;
buffer.buffer.asUint8List(offset).setAll(0, "AsciiStrng".codeUnits); offset += 10;
// [ByteData] knows no other mechanism to transfer ASCII strings in
assert((offset % SetSize) == 0); // ensure the example content fits [SetSize] bytes
}
result = buffer.buffer.asUint8List(); // only this can be used for further processing
}
}

main() {
new ConversionBenchmark().report();
}

它基于 https://github.com/dart-lang/benchmark_harness的基准测试。为了进行比较,我使用了以下Java程序,基于 https://github.com/bono8106/benchmark_harness_java的Dart基准测试工具的端口:

package ylib.tools;

import java.nio.ByteBuffer;

public class ConversionBenchmark extends BenchmarkBase {

public ByteBuffer result;

public ConversionBenchmark() { super("Conversion"); }

// The benchmark code.
@Override protected void run() {
final int BufSize = 262144; // 256kBytes
final int SetSize = 64; // one "typical" set of data, gets repeated
ByteBuffer buffer = ByteBuffer.allocate(BufSize);
double doubleContent = 0.0; // used to simulate double content
int intContent = 0; // used to simulate int content
for (int j = 0; j < (buffer.capacity() / SetSize); j++) {
// The following represents some "typical" conversion mix:
buffer.putDouble(doubleContent); doubleContent += 0.123;
for (int k = 0; k < 8; k++) { // main use case
buffer.putFloat((float)doubleContent); doubleContent += 0.123;
}
buffer.putInt(intContent); intContent++;
buffer.putInt(intContent); intContent++;
buffer.putShort((short)intContent); intContent++;
buffer.putShort((short)intContent); intContent++;
buffer.put((byte)intContent); intContent++;
buffer.put((byte)intContent); intContent++;
buffer.put("AsciiStrng".getBytes());
//assert((buffer.position() % SetSize) == 0); // ensure the example content fits [SetSize] bytes
}
buffer.flip(); // needed for further processing
result = buffer; // to avoid the compiler optimizing away everything
}

public static void main(String[] args) {
new ConversionBenchmark().report();
}
}

Java代码的运行速度几乎比我的Windows 7计算机上的Dart代码快10倍。两者均在各自的VM上以生产模式运行。

代码中是否有明显的错误?还是有不同的Dart类可以完成这项工作?关于这些简单转换为何Dart这么慢的任何解释?还是我对Dart VM性能有完全错误的期望?

最佳答案

与直接类型数组访问相比,Dart VM上字节数据方法(ByteData.setXYZByteData.getXYZ)的性能确实很差。我们开始研究该问题,初步结果令人鼓舞[1]。

同时,您可以通过使用类型化数组将自己的转换转换为big endian来解决这种不幸的性能下降问题(完整代码位于[2]):



/// Writer wraps a fixed size Uint8List and writes values into it using
/// big-endian byte order.
class Writer {
/// Output buffer.
final Uint8List out;

/// Current position within [out].
var position = 0;

Writer._create(this.out);

factory Writer(size) {
final out = new Uint8List(size);
if (Endianness.HOST_ENDIAN == Endianness.LITTLE_ENDIAN) {
return new _WriterForLEHost._create(out);
} else {
return new _WriterForBEHost._create(out);
}
}

writeFloat64(double v);

}

/// Lists used for data convertion (alias each other).
final Uint8List _convU8 = new Uint8List(8);
final Float32List _convF32 = new Float32List.view(_convU8.buffer);
final Float64List _convF64 = new Float64List.view(_convU8.buffer);

/// Writer used on little-endian host.
class _WriterForLEHost extends Writer {
_WriterForLEHost._create(out) : super._create(out);

writeFloat64(double v) {
_convF64[0] = v;
out[position + 7] = _convU8[0];
out[position + 6] = _convU8[1];
out[position + 5] = _convU8[2];
out[position + 4] = _convU8[3];
out[position + 3] = _convU8[4];
out[position + 2] = _convU8[5];
out[position + 1] = _convU8[6];
out[position + 0] = _convU8[7];
position += 8;
}
}

将这种手动转换基准化为测试,可将效率提高6倍左右:

import 'dart:typed_data';
import 'package:benchmark_harness/benchmark_harness.dart';
import 'writer.dart';

class ConversionBenchmarkManual extends BenchmarkBase {

Uint8List result;

ConversionBenchmarkManual() : super("Conversion (MANUAL)");

// The benchmark code.
void run() {
const int BufSize = 262144; // 256kBytes
const int SetSize = 64; // one "typical" set of data, gets repeated

final w = new Writer(BufSize);

double doubleContent = 0.0; // used to simulate double content
int intContent = 0; // used to simulate int content
int offset = 0;
for (int j = 0; j < (BufSize / SetSize); j++) {
// The following represents some "typical" conversion mix:
w.writeFloat64(doubleContent); doubleContent += 0.123;
for (int k = 0; k < 8; k++) { // main use case
w.writeFloat32(doubleContent); doubleContent += 0.123;
}
w.writeInt32(intContent); intContent++;
w.writeInt32(intContent); intContent++;
w.writeInt16(intContent); intContent++;
w.writeInt16(intContent); intContent++;
w.writeInt8(intContent); intContent++;
w.writeInt8(intContent); intContent++;
w.writeString("AsciiStrng");
assert((offset % SetSize) == 0); // ensure the example content fits [SetSize] bytes
}
result = w.out; // only this can be used for further processing
}
}

[1] https://code.google.com/p/dart/issues/detail?id=22107

[2] https://gist.github.com/mraleph/4eb5ccbb38904075141e

关于performance - 如何提高Dart进行二进制数据转换的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28026648/

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