Compare commits

...

2 Commits

Author SHA1 Message Date
e9c97df089 Fix issue avoiding the mod not to compile, add a test for asyncTasks (still need to be implemented)
Signed-off-by: Quentin Legot <legotquentin@gmail.com>
2023-02-03 23:52:50 +01:00
e7178d44a9 PeriodicSyncTask and AsyncPeriodicTasks should work now (untested)
Signed-off-by: Quentin Legot <legotquentin@gmail.com>
2023-02-03 23:40:01 +01:00
14 changed files with 126 additions and 81 deletions

View File

@ -5,7 +5,7 @@ public abstract class AltarikRunnable implements Runnable {
private boolean isCancelled = false;
/**
* Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.asyncTasks.AsyncTasks}
* Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.async.AsyncTasks}
* The result of this call is ignored in this case, you can still add a way to not execute its content (like if(isCancelled) return;)
*/
public void cancel() {

View File

@ -1,4 +0,0 @@
package fr.altarik.toolbox.task;
public interface AsyncTaskI extends TaskI, AutoCloseable {
}

View File

@ -8,7 +8,7 @@ public interface PeriodicTaskI extends TaskI {
* @param delay delay before starting the task
* @param period time to wait between runs
* @throws InterruptedException When executed asynchronously, task may be interrupted
* @see fr.altarik.toolbox.task.syncTasks.PeriodicSyncTask
* @see fr.altarik.toolbox.task.sync.PeriodicSyncTask
*/
public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException;
}

View File

@ -1,15 +1,29 @@
package fr.altarik.toolbox.task.syncTasks;
import fr.altarik.toolbox.task.AltarikRunnable;
package fr.altarik.toolbox.task;
public class SchedulerTaskData {
/**
* Delay before executing the function for the first time
* Correspond to tick in synchronous context and milliseconds in asynchronous context
*/
private final long delay;
/**
* Period of time before re-executing the function
* Correspond to tick in synchronous context and milliseconds in asynchronous context
*/
private final long period;
private final AltarikRunnable function;
private long currentDelay;
/**
*
* Delay and Period times corresponds to tick in synchronous context and milliseconds in asynchronous context
*
* @param function instructions to execute
* @param delay Delay before executing the function for the first time
* @param period Period of time before re-executing the function
*/
public SchedulerTaskData(AltarikRunnable function, long delay, long period) {
this.function = function;
this.delay = delay;
@ -36,4 +50,6 @@ public class SchedulerTaskData {
public long getPeriod() {
return period;
}
}

View File

@ -1,6 +1,6 @@
package fr.altarik.toolbox.task;
import fr.altarik.toolbox.task.asyncTasks.AsyncTasks;
import fr.altarik.toolbox.task.async.AsyncTasks;
import net.fabricmc.api.ModInitializer;
public class Task implements ModInitializer {

View File

@ -1,6 +1,8 @@
package fr.altarik.toolbox.task.asyncTasks;
package fr.altarik.toolbox.task.async;
import fr.altarik.toolbox.task.*;
import fr.altarik.toolbox.task.AltarikRunnable;
import fr.altarik.toolbox.task.PeriodicTaskI;
import fr.altarik.toolbox.task.TaskI;
import it.unimi.dsi.fastutil.ints.IntComparators;
import java.util.ArrayList;
@ -56,7 +58,7 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI {
@Override
public void addTask(AltarikRunnable function) throws InterruptedException {
this.addTask(function, 0, 1);
this.addTask(function, 0, 1000);
}
@Override

View File

@ -0,0 +1,6 @@
package fr.altarik.toolbox.task.async;
import fr.altarik.toolbox.task.TaskI;
public interface AsyncTaskI extends TaskI, AutoCloseable {
}

View File

@ -1,7 +1,6 @@
package fr.altarik.toolbox.task.asyncTasks;
package fr.altarik.toolbox.task.async;
import fr.altarik.toolbox.task.AltarikRunnable;
import fr.altarik.toolbox.task.TaskI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -10,7 +9,7 @@ import java.util.concurrent.TimeUnit;
/**
* A non-blocking small sized time-consuming tasks to executed asynchronously.
*/
public class AsyncTasks implements TaskI {
public class AsyncTasks implements AsyncTaskI {
private final ExecutorService worker;
@ -30,11 +29,11 @@ public class AsyncTasks implements TaskI {
*
* @return an instance of AsyncTasks
*/
public static TaskI initialize(int numberOfWorker) {
public static AsyncTaskI initialize(int numberOfWorker) {
return new AsyncTasks(numberOfWorker);
}
public static TaskI initialize() {
public static AsyncTaskI initialize() {
return initialize(Runtime.getRuntime().availableProcessors());
}

View File

@ -1,16 +1,27 @@
package fr.altarik.toolbox.task;
package fr.altarik.toolbox.task.async;
import fr.altarik.toolbox.task.syncTasks.SchedulerTaskData;
import fr.altarik.toolbox.task.AltarikRunnable;
import fr.altarik.toolbox.task.SchedulerTaskData;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Vector;
public class TaskScheduler {
private Vector<SchedulerTaskData> asyncTasks;
/**
* Return last time the method was executed, Value initialized to now when using sending the task to scheduler
*/
private HashMap<SchedulerTaskData, Instant> lastTimeExecution;
private boolean stop = false;
public synchronized void sendAsyncTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
asyncTasks.addElement(new SchedulerTaskData(function, delay, period));
SchedulerTaskData data = new SchedulerTaskData(function, delay, period);
asyncTasks.addElement(data);
lastTimeExecution.put(new SchedulerTaskData(function, delay, period), Instant.now());
notify();
}
@ -30,12 +41,13 @@ public class TaskScheduler {
asyncTasks.remove(data);
if(!data.getFunction().isCancelled()) {
long currentDelay = data.getCurrentDelay();
if(currentDelay != 0) {
data.setCurrentDelay(currentDelay - 1);
asyncTasks.addElement(data);
} else {
Instant currentTime = Instant.now();
Instant lastExecution = lastTimeExecution.get(data);
// (lastExec + delay) - currentTime
if(lastExecution.plus(currentDelay, ChronoUnit.MILLIS).isBefore(currentTime)) {
data.getFunction().run();
data.setCurrentDelay(data.getPeriod());
lastTimeExecution.put(data, Instant.now());
asyncTasks.addElement(data);
}
}

View File

@ -0,0 +1,57 @@
package fr.altarik.toolbox.task.sync;
import fr.altarik.toolbox.task.AltarikRunnable;
import fr.altarik.toolbox.task.PeriodicTaskI;
import fr.altarik.toolbox.task.SchedulerTaskData;
import fr.altarik.toolbox.task.TaskI;
import java.util.ArrayList;
import java.util.List;
public class PeriodicSyncTask implements PeriodicTaskI, Runnable {
private ServerTickListener listener;
private List<SchedulerTaskData> tasks;
private PeriodicSyncTask() {
this.listener = new ServerTickListener(this);
this.tasks = new ArrayList<>(2);
}
public static TaskI initialize() {
return new PeriodicSyncTask();
}
@Override
public void addTask(AltarikRunnable function) throws InterruptedException {
addTask(function, 0, 1);
}
@Override
public void run() {
List<SchedulerTaskData> removeList = new ArrayList<>(tasks.size());
for(SchedulerTaskData data : tasks) {
if(!data.getFunction().isCancelled()) {
long currentDelay = data.getCurrentDelay();
if(currentDelay != 0) {
data.setCurrentDelay(currentDelay - 1);
} else {
data.getFunction().run();
data.setCurrentDelay(data.getPeriod());
}
} else {
removeList.add(data);
}
}
for(SchedulerTaskData toRemove : removeList) {
tasks.remove(toRemove);
}
}
@Override
public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
tasks.add(new SchedulerTaskData(function, delay, period));
}
}

View File

@ -1,4 +1,4 @@
package fr.altarik.toolbox.task.syncTasks;
package fr.altarik.toolbox.task.sync;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
@ -13,7 +13,7 @@ public class ServerTickListener {
}
private void onServerTick(MinecraftServer minecraftServer) {
task.run();
}
}

View File

@ -1,48 +0,0 @@
package fr.altarik.toolbox.task.syncTasks;
import fr.altarik.toolbox.task.AltarikRunnable;
import fr.altarik.toolbox.task.PeriodicTaskI;
import fr.altarik.toolbox.task.TaskI;
import java.util.ArrayList;
import java.util.List;
public class PeriodicSyncTask implements PeriodicTaskI, Runnable {
private ServerTickListener listener;
private List<AltarikRunnable> tasks;
private PeriodicSyncTask() {
this.listener = new ServerTickListener(this);
this.tasks = new ArrayList<>(2);
}
public static TaskI initialize() {
return new PeriodicSyncTask();
}
@Override
public void addTask(AltarikRunnable function) throws InterruptedException {
tasks.add(function);
}
@Override
public void run() {
List<AltarikRunnable> removeList = new ArrayList<>(tasks.size());
for(AltarikRunnable task : tasks) {
if(task.isCancelled()) {
removeList.add(task);
} else {
task.run();
}
}
tasks.removeAll(removeList);
}
@Override
public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
}
}

View File

@ -1,8 +1,7 @@
package fr.altarik.toolbox;
package fr.altarik.toolbox.task;
import fr.altarik.toolbox.task.AltarikRunnable;
import fr.altarik.toolbox.task.TaskI;
import fr.altarik.toolbox.task.asyncTasks.AsyncTasks;
import fr.altarik.toolbox.task.async.AsyncTaskI;
import fr.altarik.toolbox.task.async.AsyncTasks;
import org.junit.jupiter.api.Test;
import java.util.Date;
@ -21,7 +20,7 @@ class AsyncTaskTest {
void testAsyncOp() throws Exception {
int numberOfTasks = 10000;
System.out.println("Initializing async tasks worker");
TaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want
AsyncTaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want
Stack<Integer> results = new Stack<>();
for(int i = 0; i < numberOfTasks; i++) {
System.out.println(log("sending task " + i));
@ -40,6 +39,5 @@ class AsyncTaskTest {
expected[i] = i;
}
assertArrayEquals(expected, results.toArray());
}
}

View File

@ -0,0 +1,7 @@
package fr.altarik.toolbox.task;
public class SyncTaskTest {
// TODO: 03/02/2023 Envoyé les tasks au workers grâce à un autre thread.
}