dart代码转为java,如何提高Dart数据转换性能/从二进制?

Doing some consulting work for a bigger German companies Future Technologies Group I have ported about 6000 lines of Java server side software to Dart. This should help to answer the question whether Dart can efficiently be used on the server. (Which itself would give a green light for Dart due to the searched for advantage of having one language for client and server side programming.)

Learning about Dart (which I really enjoyed working with) gave me an expectation of a performance penalty of 30-50% relative to Java but in any case no worse than 100% (twice as slow) which is the cutoff for the decision process mentioned above.

The port went smoothly. I learned a lot. Unit tests were fine. But the performance turned out to be extremly bad ... SEVEN times slower overall compared to the Java program.

Profiling the code revealed two main culprits: data conversion and file I/O. Maybe I'm doing something wrong? Before I go back to my client and they cancel their Dart research I would like to search some advice on how to improve things. Let's start with data conversion, the conversion of native Dart data types into various binary formats which can be used for effective transfer and storage of data.

Usually these conversions are simple and very fast because nothing has really to be converted from the used internal format but mostly stored into a buffer. I created a benchmark program which somehow reflects the typical use of these conversions in my program:

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();

}

It is based on the benchmark harness from https://github.com/dart-lang/benchmark_harness. For comparisions I used the following Java program based on a port of the Dart benchmark harness from https://github.com/bono8106/benchmark_harness_java:

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();

}

}

The Java code runs almost exactly 10 times faster than the Dart code on my Intel Windows 7 machine. Both run in production mode on their respective VMs.

Is there an obvious error in the code? Or are there different Dart classes available to do the job? Any explanation as to why Dart is so much slower with these simple conversions? Or do I have completely wrong expectations with respect to Dart VM performance?

解决方案

It is true that performance of byte data methods (ByteData.setXYZ and ByteData.getXYZ) is pretty bad on Dart VM compared to direct typed array access. We started working on the issue and initial results are promising[1].

In the mean time you can work around this unfortunate performance regression by rolling your own conversion to big endian using typed arrays (full code at[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;

}

}

Benchmarking this manual conversion on your test yields around 6x improvement:

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

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值