Skip to content

Commit dde7ee0

Browse files
committed
- Consider using ForkJoinPool in the case of a large number of asynchronous tasks.
- Adjust the synchronization mode of some TileEntities to use markNoUpdate instead of markForUpdate. - Tweak TileUpgradeBus to fix occasional CME issues.
1 parent 295b703 commit dde7ee0

File tree

12 files changed

+184
-114
lines changed

12 files changed

+184
-114
lines changed

src/main/java/github/kasuminova/mmce/common/concurrent/TaskExecutor.java

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.netty.util.internal.ThrowableUtil;
77
import io.netty.util.internal.shaded.org.jctools.queues.atomic.MpscLinkedAtomicQueue;
88
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
9+
import it.unimi.dsi.fastutil.objects.ObjectIterator;
910
import net.minecraftforge.fml.common.eventhandler.EventPriority;
1011
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
1112
import net.minecraftforge.fml.common.gameevent.TickEvent;
@@ -47,6 +48,7 @@ public class TaskExecutor {
4748
private final TaskSubmitter submitter = new TaskSubmitter();
4849

4950
private volatile boolean inTick = false;
51+
private volatile boolean shouldUseForkJoinPool = false;
5052

5153
public void init() {
5254
THREAD_POOL.prestartAllCoreThreads();
@@ -76,6 +78,36 @@ public void onServerTick(final TickEvent.ServerTickEvent event) {
7678
}
7779

7880
executeGroups.clear();
81+
checkShouldUseForkJoinPool();
82+
}
83+
84+
/**
85+
* <p>大量任务的前提下,使用阻塞队列会导致 CPU 资源占用的激增,此时我们不再关注优先级,而是考虑尽可能快地提交任务。</p>
86+
*
87+
* <p>With a large number of tasks, the use of a blocking queue can lead to a spike in CPU resource usage, at which
88+
* point we stop focusing on prioritization and think about submitting tasks as fast as possible.</p>
89+
*/
90+
private void checkShouldUseForkJoinPool() {
91+
if (tickExisted % 20 != 0) {
92+
return;
93+
}
94+
95+
if (shouldUseForkJoinPool) {
96+
if (!shouldUseForkJoinPool()) {
97+
ModularMachinery.log.warn("The thread pool has been re-switched to ThreadPoolExecutor (below the limit of 1500).");
98+
shouldUseForkJoinPool = false;
99+
}
100+
return;
101+
}
102+
if (shouldUseForkJoinPool()) {
103+
ModularMachinery.log.warn("The thread pool has now been replaced with a ForkJoinPool due to too many tasks in a single commit (Limit 1500).");
104+
shouldUseForkJoinPool = true;
105+
}
106+
}
107+
108+
private boolean shouldUseForkJoinPool() {
109+
long executedAvgPerExecution = executedCount == 0 ? 0 : totalExecuted / executedCount;
110+
return executedAvgPerExecution >= 1500;
79111
}
80112

81113
/**
@@ -201,8 +233,7 @@ public ActionExecutor addExecuteGroupTask(final Action action, final long groupI
201233
}
202234
}
203235

204-
ActionExecutor actionExecutor = new ActionExecutor(action);
205-
return group.offer(actionExecutor);
236+
return group.offer(new ActionExecutor(action));
206237
}
207238

208239
public <T> ForkJoinTask<T> submitForkJoinTask(final ForkJoinTask<T> task) {
@@ -227,10 +258,18 @@ public void addTEMarkNoUpdateTask(final TileEntitySynchronized te) {
227258
requireMarkNoUpdateTEQueue.offer(te);
228259
}
229260

261+
private void execute(final ActionExecutor executor) {
262+
if (shouldUseForkJoinPool) {
263+
FORK_JOIN_POOL.execute(executor);
264+
} else {
265+
THREAD_POOL.execute(executor);
266+
}
267+
}
268+
230269
private synchronized void submitTask() {
231270
ActionExecutor executor;
232271
while ((executor = executors.poll()) != null) {
233-
THREAD_POOL.execute(executor);
272+
execute(executor);
234273
submitted.offer(executor);
235274
}
236275

@@ -240,10 +279,15 @@ private synchronized void submitTask() {
240279
}
241280

242281
synchronized (executeGroups) {
243-
for (final ExecuteGroup group : executeGroups.values()) {
282+
for (ObjectIterator<ExecuteGroup> it = executeGroups.values().iterator(); it.hasNext(); ) {
283+
final ExecuteGroup group = it.next();
244284
if (group.isSubmitted()) {
245285
continue;
246286
}
287+
if (group.isEmpty()) {
288+
it.remove();
289+
continue;
290+
}
247291
ActionExecutor groupExecutor = new ActionExecutor(() -> {
248292
ActionExecutor actionExecutor;
249293
while ((actionExecutor = group.poll()) != null) {
@@ -252,7 +296,7 @@ private synchronized void submitTask() {
252296
group.setSubmitted(false);
253297
});
254298
group.setSubmitted(true);
255-
THREAD_POOL.execute(groupExecutor);
299+
execute(groupExecutor);
256300
submitted.offer(groupExecutor);
257301
}
258302
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package github.kasuminova.mmce.common.handler;
2+
3+
import hellfirepvp.modularmachinery.common.item.ItemBlockController;
4+
import hellfirepvp.modularmachinery.common.lib.ItemsMM;
5+
import net.minecraft.client.Minecraft;
6+
import net.minecraft.client.entity.EntityPlayerSP;
7+
import net.minecraft.client.resources.I18n;
8+
import net.minecraft.item.Item;
9+
import net.minecraft.item.ItemStack;
10+
import net.minecraft.nbt.NBTTagCompound;
11+
import net.minecraft.util.text.TextFormatting;
12+
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
13+
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
14+
import net.minecraftforge.fml.relauncher.Side;
15+
import net.minecraftforge.fml.relauncher.SideOnly;
16+
17+
import java.util.UUID;
18+
19+
public class ClientHandler {
20+
21+
@SubscribeEvent
22+
@SideOnly(Side.CLIENT)
23+
public void onMEItemBusItemTooltip(ItemTooltipEvent event) {
24+
ItemStack stack = event.getItemStack();
25+
Item item = stack.getItem();
26+
if (item != ItemsMM.meItemInputBus && item != ItemsMM.meItemOutputBus) {
27+
return;
28+
}
29+
30+
if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("inventory")) {
31+
event.getToolTip().add(I18n.format("gui.meitembus.nbt_stored"));
32+
}
33+
}
34+
35+
@SubscribeEvent
36+
@SideOnly(Side.CLIENT)
37+
public void onBlockControllerItemTooltip(ItemTooltipEvent event) {
38+
ItemStack stack = event.getItemStack();
39+
Item item = stack.getItem();
40+
if (!(item instanceof ItemBlockController)) {
41+
return;
42+
}
43+
44+
NBTTagCompound tag = stack.getTagCompound();
45+
if (tag != null && tag.hasKey("owner")) {
46+
String ownerUUIDStr = tag.getString("owner");
47+
try {
48+
UUID ownerUUID = UUID.fromString(ownerUUIDStr);
49+
50+
EntityPlayerSP player = Minecraft.getMinecraft().player;
51+
UUID playerUUID = player.getGameProfile().getId();
52+
if (playerUUID.equals(ownerUUID)) {
53+
event.getToolTip().add(I18n.format("tooltip.item.controller.owner.self"));
54+
} else {
55+
event.getToolTip().add(I18n.format("tooltip.item.controller.owner.not_self"));
56+
}
57+
} catch (Exception e) {
58+
event.getToolTip().add(TextFormatting.RED + "NBT read error.");
59+
}
60+
}
61+
}
62+
63+
}

src/main/java/github/kasuminova/mmce/common/handler/EventHandler.java

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,33 @@
77
import hellfirepvp.modularmachinery.common.block.BlockController;
88
import hellfirepvp.modularmachinery.common.container.ContainerBase;
99
import hellfirepvp.modularmachinery.common.item.ItemBlockController;
10-
import hellfirepvp.modularmachinery.common.lib.ItemsMM;
1110
import hellfirepvp.modularmachinery.common.tiles.base.SelectiveUpdateTileEntity;
1211
import hellfirepvp.modularmachinery.common.tiles.base.TileEntitySynchronized;
1312
import hellfirepvp.modularmachinery.common.tiles.base.TileMultiblockMachineController;
14-
import net.minecraft.client.Minecraft;
15-
import net.minecraft.client.entity.EntityPlayerSP;
16-
import net.minecraft.client.resources.I18n;
1713
import net.minecraft.entity.player.EntityPlayer;
1814
import net.minecraft.entity.player.EntityPlayerMP;
1915
import net.minecraft.inventory.Container;
20-
import net.minecraft.item.Item;
2116
import net.minecraft.item.ItemStack;
2217
import net.minecraft.nbt.NBTTagCompound;
2318
import net.minecraft.tileentity.TileEntity;
2419
import net.minecraft.util.math.BlockPos;
25-
import net.minecraft.util.text.TextFormatting;
2620
import net.minecraft.world.World;
27-
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
2821
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
2922
import net.minecraftforge.event.world.BlockEvent;
3023
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
3124
import net.minecraftforge.fml.common.gameevent.TickEvent;
3225
import net.minecraftforge.fml.relauncher.Side;
33-
import net.minecraftforge.fml.relauncher.SideOnly;
3426

3527
import java.util.UUID;
3628

3729
@SuppressWarnings("MethodMayBeStatic")
3830
public class EventHandler {
31+
private static boolean checkTERange(final EntityPlayer player, final TileEntity te) {
32+
BlockPos tePos = te.getPos();
33+
BlockPos playerPos = player.getPosition();
34+
return tePos.getDistance(playerPos.getX(), playerPos.getY(), playerPos.getZ()) >= 6.0D;
35+
}
36+
3937
@SubscribeEvent
4038
public void onPlayerRightClickBlock(PlayerInteractEvent.RightClickBlock event) {
4139
World world = event.getWorld();
@@ -55,7 +53,7 @@ public void onPlayerRightClickBlock(PlayerInteractEvent.RightClickBlock event) {
5553
*/
5654
@SubscribeEvent
5755
public void onPlayerTick(TickEvent.PlayerTickEvent event) {
58-
if (event.phase != TickEvent.Phase.START || event.side == Side.CLIENT) {
56+
if (event.phase != TickEvent.Phase.START || event.side != Side.SERVER) {
5957
return;
6058
}
6159

@@ -155,52 +153,4 @@ public void onBlockPlaced(BlockEvent.PlaceEvent event) {
155153
ModularMachinery.log.warn("Invalid owner uuid " + ownerUUIDStr, e);
156154
}
157155
}
158-
159-
@SubscribeEvent
160-
@SideOnly(Side.CLIENT)
161-
public void onMEItemBusItemTooltip(ItemTooltipEvent event) {
162-
ItemStack stack = event.getItemStack();
163-
Item item = stack.getItem();
164-
if (item != ItemsMM.meItemInputBus && item != ItemsMM.meItemOutputBus) {
165-
return;
166-
}
167-
168-
if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("inventory")) {
169-
event.getToolTip().add(I18n.format("gui.meitembus.nbt_stored"));
170-
}
171-
}
172-
173-
@SubscribeEvent
174-
@SideOnly(Side.CLIENT)
175-
public void onBlockControllerItemTooltip(ItemTooltipEvent event) {
176-
ItemStack stack = event.getItemStack();
177-
Item item = stack.getItem();
178-
if (!(item instanceof ItemBlockController)) {
179-
return;
180-
}
181-
182-
NBTTagCompound tag = stack.getTagCompound();
183-
if (tag != null && tag.hasKey("owner")) {
184-
String ownerUUIDStr = tag.getString("owner");
185-
try {
186-
UUID ownerUUID = UUID.fromString(ownerUUIDStr);
187-
188-
EntityPlayerSP player = Minecraft.getMinecraft().player;
189-
UUID playerUUID = player.getGameProfile().getId();
190-
if (playerUUID.equals(ownerUUID)) {
191-
event.getToolTip().add(I18n.format("tooltip.item.controller.owner.self"));
192-
} else {
193-
event.getToolTip().add(I18n.format("tooltip.item.controller.owner.not_self"));
194-
}
195-
} catch (Exception e) {
196-
event.getToolTip().add(TextFormatting.RED + "NBT read error.");
197-
}
198-
}
199-
}
200-
201-
private static boolean checkTERange(final EntityPlayer player, final TileEntity te) {
202-
BlockPos tePos = te.getPos();
203-
BlockPos playerPos = player.getPosition();
204-
return tePos.getDistance(playerPos.getX(), playerPos.getY(), playerPos.getZ()) >= 6.0D;
205-
}
206156
}

src/main/java/github/kasuminova/mmce/common/tile/base/MEFluidBus.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public void updateSetting(final IConfigManager manager, final Enum settingName,
114114
@Override
115115
public void onChangeInventory(final IItemHandler inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack) {
116116
updateTankCapacity();
117-
markForUpdateSync();
117+
markNoUpdateSync();
118118
}
119119

120120
private void updateTankCapacity() {
@@ -124,7 +124,7 @@ private void updateTankCapacity() {
124124

125125
@Override
126126
public void onFluidInventoryChanged(final IAEFluidTank inv, final int slot) {
127-
markForUpdateSync();
127+
markNoUpdateSync();
128128
}
129129

130130
@Override

src/main/java/github/kasuminova/mmce/common/util/concurrent/ExecuteGroup.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package github.kasuminova.mmce.common.util.concurrent;
22

3-
import io.netty.util.internal.shaded.org.jctools.queues.atomic.MpscLinkedAtomicQueue;
4-
53
import java.util.Queue;
4+
import java.util.concurrent.ConcurrentLinkedQueue;
65
import java.util.concurrent.atomic.AtomicLong;
76

87
public class ExecuteGroup {
98
private static final AtomicLong GROUP_COUNTER = new AtomicLong(0);
9+
1010
private final long groupId;
11-
private final Queue<ActionExecutor> executors = new MpscLinkedAtomicQueue<>();
11+
private final Queue<ActionExecutor> executors = new ConcurrentLinkedQueue<>();
1212

1313
private volatile boolean submitted = false;
1414

src/main/java/github/kasuminova/mmce/common/world/MachineComponentManager.java

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,31 +48,34 @@ public void checkComponentShared(TileEntity component, TileMultiblockMachineCont
4848
if (!info.areTileEntityEquals(component)) {
4949
ComponentInfo newInfo = new ComponentInfo(component, pos, new ObjectArraySet<>(Collections.singleton(ctrl)));
5050
posComponentMap.put(pos, newInfo);
51-
} else {
52-
Set<TileMultiblockMachineController> owners = info.owners;
53-
if (owners.contains(ctrl)) {
51+
return;
52+
}
53+
54+
Set<TileMultiblockMachineController> owners = info.owners;
55+
if (owners.contains(ctrl)) {
56+
return;
57+
}
58+
59+
synchronized (owners) {
60+
owners.add(ctrl);
61+
if (owners.size() <= 1) {
5462
return;
5563
}
5664

57-
synchronized (owners) {
58-
owners.add(ctrl);
59-
if (owners.size() > 1) {
60-
long groupId = -1;
61-
for (final TileMultiblockMachineController owner : owners) {
62-
if (owner.getExecuteGroupId() != -1) {
63-
groupId = owner.getExecuteGroupId();
64-
}
65-
}
66-
67-
if (groupId == -1) {
68-
groupId = ExecuteGroup.newGroupId();
69-
}
70-
71-
for (final TileMultiblockMachineController owner : owners) {
72-
owner.setExecuteGroupId(groupId);
73-
}
65+
long groupId = -1;
66+
for (final TileMultiblockMachineController owner : owners) {
67+
if (owner.getExecuteGroupId() != -1) {
68+
groupId = owner.getExecuteGroupId();
7469
}
7570
}
71+
72+
if (groupId == -1) {
73+
groupId = ExecuteGroup.newGroupId();
74+
}
75+
76+
for (final TileMultiblockMachineController owner : owners) {
77+
owner.setExecuteGroupId(groupId);
78+
}
7679
}
7780
}
7881

src/main/java/hellfirepvp/modularmachinery/client/ClientProxy.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import github.kasuminova.mmce.client.gui.GuiMEItemOutputBus;
1515
import github.kasuminova.mmce.client.renderer.MachineControllerRenderer;
1616
import github.kasuminova.mmce.client.resource.GeoModelExternalLoader;
17+
import github.kasuminova.mmce.common.handler.ClientHandler;
1718
import github.kasuminova.mmce.common.tile.MEFluidInputBus;
1819
import github.kasuminova.mmce.common.tile.MEFluidOutputBus;
1920
import github.kasuminova.mmce.common.tile.MEItemInputBus;
@@ -151,6 +152,8 @@ public void preInit() {
151152
MinecraftForge.EVENT_BUS.register(this);
152153
MinecraftForge.EVENT_BUS.register(new DebugOverlayHelper());
153154
MinecraftForge.EVENT_BUS.register(new SelectionBoxRenderHelper());
155+
MinecraftForge.EVENT_BUS.register(new ClientHandler());
156+
154157
if (Mods.JEI.isPresent()) {
155158
registerJEIEventHandler();
156159
}

0 commit comments

Comments
 (0)