feat: 轻量化 ScaledProcessingPattern,改为最小字段与延迟计算,

减少构造时的大量临时对象分配,降低 GC 压力并提升高并发/多 provider 场景下的性能
This commit is contained in:
C-H716 2025-09-03 23:13:39 +08:00
parent ef8fa756ed
commit d4095e64ea
3 changed files with 110 additions and 85 deletions

View File

@ -17,27 +17,21 @@ import java.util.Objects;
*/ */
public final class ScaledProcessingPattern implements IPatternDetails { public final class ScaledProcessingPattern implements IPatternDetails {
private final AEProcessingPattern original; // 原始样板引用 // 最小化实例字段只保留原始样板引用定义和倍数
private final AEItemKey definition; // 样板物品 private final AEProcessingPattern original; // 原始样板引用
private final GenericStack[] sparseInputs; // 缩放后的稀疏输入 private final AEItemKey definition; // 样板物品直接委托自 original
private final GenericStack[] sparseOutputs; // 缩放后的稀疏输出 private final long multiplier; // 乘数外部可视为视图参数
private final IInput[] inputs; // 缩放后的压缩输入
private final GenericStack[] condensedOutputs; // 缩放后的压缩输出
public ScaledProcessingPattern( // 延迟计算缓存轻量化实例时避免在构造器中分配大数组
AEProcessingPattern original, private transient volatile IInput[] inputsCache;
AEItemKey definition, private transient volatile GenericStack[] outputsCache;
GenericStack[] sparseInputs, private transient volatile GenericStack[] sparseInputsCache;
GenericStack[] sparseOutputs, private transient volatile GenericStack[] sparseOutputsCache;
IInput[] inputs,
GenericStack[] condensedOutputs public ScaledProcessingPattern(AEProcessingPattern original, AEItemKey definition, long multiplier) {
) {
this.original = Objects.requireNonNull(original); this.original = Objects.requireNonNull(original);
this.definition = Objects.requireNonNull(definition); this.definition = Objects.requireNonNull(definition);
this.sparseInputs = Objects.requireNonNull(sparseInputs); this.multiplier = multiplier <= 0 ? 1L : multiplier;
this.sparseOutputs = Objects.requireNonNull(sparseOutputs);
this.inputs = Objects.requireNonNull(inputs);
this.condensedOutputs = Objects.requireNonNull(condensedOutputs);
} }
/* -------------------- API 实现 -------------------- */ /* -------------------- API 实现 -------------------- */
@ -53,25 +47,91 @@ public final class ScaledProcessingPattern implements IPatternDetails {
@Override @Override
public IInput[] getInputs() { public IInput[] getInputs() {
return inputs; IInput[] cached = this.inputsCache;
if (cached == null) {
synchronized (this) {
cached = this.inputsCache;
if (cached == null) {
var base = original.getInputs();
IInput[] arr = new IInput[base.length];
for (int i = 0; i < base.length; i++) {
var in = base[i];
// 不复制 template 数组直接复用原始的 possible inputs仅放大 multiplier
arr[i] = new Input(in.getPossibleInputs(), in.getMultiplier() * this.multiplier);
}
this.inputsCache = arr;
cached = arr;
}
}
}
return cached;
} }
@Override @Override
public GenericStack[] getOutputs() { public GenericStack[] getOutputs() {
return condensedOutputs; GenericStack[] cached = this.outputsCache;
if (cached == null) {
synchronized (this) {
cached = this.outputsCache;
if (cached == null) {
var baseOutputs = original.getOutputs();
GenericStack[] arr = new GenericStack[baseOutputs.length];
for (int i = 0; i < baseOutputs.length; i++) {
var o = baseOutputs[i];
if (o != null) arr[i] = new GenericStack(o.what(), o.amount() * this.multiplier);
}
this.outputsCache = arr;
cached = arr;
}
}
}
return cached;
} }
public GenericStack[] getSparseInputs() { public GenericStack[] getSparseInputs() {
return sparseInputs; GenericStack[] cached = this.sparseInputsCache;
if (cached == null) {
synchronized (this) {
cached = this.sparseInputsCache;
if (cached == null) {
var base = original.getSparseInputs();
GenericStack[] arr = new GenericStack[base.length];
for (int i = 0; i < base.length; i++) {
var v = base[i];
if (v != null) arr[i] = new GenericStack(v.what(), v.amount() * this.multiplier);
}
this.sparseInputsCache = arr;
cached = arr;
}
}
}
return cached;
} }
public GenericStack[] getSparseOutputs() { public GenericStack[] getSparseOutputs() {
return sparseOutputs; GenericStack[] cached = this.sparseOutputsCache;
if (cached == null) {
synchronized (this) {
cached = this.sparseOutputsCache;
if (cached == null) {
var base = original.getSparseOutputs();
GenericStack[] arr = new GenericStack[base.length];
for (int i = 0; i < base.length; i++) {
var v = base[i];
if (v != null) arr[i] = new GenericStack(v.what(), v.amount() * this.multiplier);
}
this.sparseOutputsCache = arr;
cached = arr;
}
}
}
return cached;
} }
@Override @Override
public GenericStack getPrimaryOutput() { public GenericStack getPrimaryOutput() {
if (condensedOutputs.length > 0) return condensedOutputs[0]; var outs = getOutputs();
if (outs.length > 0 && outs[0] != null) return outs[0];
return original.getPrimaryOutput(); return original.getPrimaryOutput();
} }
@ -82,26 +142,29 @@ public final class ScaledProcessingPattern implements IPatternDetails {
@Override @Override
public void pushInputsToExternalInventory(KeyCounter[] inputHolder, PatternInputSink inputSink) { public void pushInputsToExternalInventory(KeyCounter[] inputHolder, PatternInputSink inputSink) {
// 保持和 AEProcessingPattern 一致 sparseInputs 驱动 // 使用 lazy 计算的 sparseInputs inputs 来驱动当两者长度一致时直接委托
if (sparseInputs.length == inputs.length) { GenericStack[] sInputs = getSparseInputs();
IInput[] ins = getInputs();
if (sInputs.length == ins.length) {
IPatternDetails.super.pushInputsToExternalInventory(inputHolder, inputSink); IPatternDetails.super.pushInputsToExternalInventory(inputHolder, inputSink);
} else { return;
KeyCounter allInputs = new KeyCounter(); }
for (KeyCounter counter : inputHolder) {
allInputs.addAll(counter); KeyCounter allInputs = new KeyCounter();
} for (KeyCounter counter : inputHolder) {
for (GenericStack sparseInput : sparseInputs) { allInputs.addAll(counter);
if (sparseInput != null) { }
AEKey key = sparseInput.what(); for (GenericStack sparseInput : sInputs) {
long amount = sparseInput.amount(); if (sparseInput != null) {
long available = allInputs.get(key); AEKey key = sparseInput.what();
if (available < amount) { long amount = sparseInput.amount();
throw new RuntimeException("Expected at least %d of %s when pushing scaled pattern, but only %d available" long available = allInputs.get(key);
.formatted(amount, key, available)); if (available < amount) {
} throw new RuntimeException("Expected at least %d of %s when pushing scaled pattern, but only %d available"
inputSink.pushInput(key, amount); .formatted(amount, key, available));
allInputs.remove(key, amount);
} }
inputSink.pushInput(key, amount);
allInputs.remove(key, amount);
} }
} }
} }
@ -117,18 +180,22 @@ public final class ScaledProcessingPattern implements IPatternDetails {
this.multiplier = multiplier; this.multiplier = multiplier;
} }
@Override
public GenericStack[] getPossibleInputs() { public GenericStack[] getPossibleInputs() {
return this.template; return this.template;
} }
@Override
public long getMultiplier() { public long getMultiplier() {
return this.multiplier; return this.multiplier;
} }
@Override
public boolean isValid(AEKey input, Level level) { public boolean isValid(AEKey input, Level level) {
return input.matches(this.template[0]); return input.matches(this.template[0]);
} }
@Override
public @Nullable AEKey getRemainingKey(AEKey template) { public @Nullable AEKey getRemainingKey(AEKey template) {
return null; return null;
} }

View File

@ -71,48 +71,7 @@ public final class PatternScaler {
// 配置读取异常时不施加上限 // 配置读取异常时不施加上限
} }
// 构建压缩输入将每个输入的 multiplier 翻倍保留每个模板的原始数量 // 仅使用 multiplier 构建轻量化 ScaledProcessingPattern具体视图按需计算
IInput[] scaledInputs = new IInput[baseInputs.length]; return new ScaledProcessingPattern(base, base.getDefinition(), multiplier);
for (int i = 0; i < baseInputs.length; i++) {
var in = baseInputs[i];
var template = in.getPossibleInputs();
GenericStack[] scaledTemplates = new GenericStack[template.length];
for (int j = 0; j < template.length; j++) {
scaledTemplates[j] = new GenericStack(template[j].what(), template[j].amount());
}
scaledInputs[i] = new ScaledProcessingPattern.Input(scaledTemplates, in.getMultiplier() * multiplier);
}
/* 4. 构建压缩输出 */
GenericStack[] scaledCondensedOutputs = new GenericStack[baseOutputs.length];
for (int i = 0; i < baseOutputs.length; i++) {
GenericStack out = baseOutputs[i];
if (out != null) {
scaledCondensedOutputs[i] = new GenericStack(out.what(), out.amount() * multiplier);
}
}
// 构建并打印稀疏表示直接按 multiplier 放大
GenericStack[] scaledSparseInputs = new GenericStack[baseSparseInputs.length];
for (int i = 0; i < baseSparseInputs.length; i++) {
var in = baseSparseInputs[i];
if (in != null) {
scaledSparseInputs[i] = new GenericStack(in.what(), in.amount() * multiplier);
}
}
GenericStack[] scaledSparseOutputs = new GenericStack[baseSparseOutputs.length];
for (int i = 0; i < baseSparseOutputs.length; i++) {
var out = baseSparseOutputs[i];
if (out != null) {
scaledSparseOutputs[i] = new GenericStack(out.what(), out.amount() * multiplier);
}
}
return new ScaledProcessingPattern(base,
base.getDefinition(),
scaledSparseInputs,
scaledSparseOutputs,
scaledInputs,
scaledCondensedOutputs);
} }
} }

View File

@ -42,7 +42,6 @@
"ae2.autopattern.CraftingTreeNodeMixin", "ae2.autopattern.CraftingTreeNodeMixin",
"ae2.autopattern.CraftingTreeProcessMixin", "ae2.autopattern.CraftingTreeProcessMixin",
"ae2.autopattern.PatternProviderLogicContainsRedirectMixin", "ae2.autopattern.PatternProviderLogicContainsRedirectMixin",
"ae2.autopattern.adaptation.AdvPatternProviderLogicContainsRedirectMixin",
"ae2.helpers.PatternProviderLogicAdvancedMixin", "ae2.helpers.PatternProviderLogicAdvancedMixin",
"ae2.helpers.PatternProviderLogicDoublingMixin", "ae2.helpers.PatternProviderLogicDoublingMixin",
"ae2.menu.ContainerPatternEncodingTermMenuMixin", "ae2.menu.ContainerPatternEncodingTermMenuMixin",