Merge remote-tracking branch 'origin/test' into restruct-new

# Conflicts:
#	src/main/java/club/joylink/rtss/simulation/job/SimulationScheduledJob.java
This commit is contained in:
walker-sheng 2021-05-11 15:06:42 +08:00
commit 4cb457ab16
5 changed files with 74 additions and 83 deletions

View File

@ -133,7 +133,12 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
try { try {
this.mainLogicRunning.set(true); this.mainLogicRunning.set(true);
this.systemTime = this.systemTime.plusNanos(timeAdd); this.systemTime = this.systemTime.plusNanos(timeAdd);
this.jobMap.values().forEach(SimulationJob::run); this.jobMap.values().forEach(simulationJob -> {
if (getSystemTime().compareTo(simulationJob.runtime) >= 0) {
simulationJob.job.run();
simulationJob.afterRun();
}
});
} catch (Throwable e) { } catch (Throwable e) {
this.runError(e); this.runError(e);
log.error(String.format("仿真[%s]主线程逻辑执行异常,仿真停止运行", this.id), e); log.error(String.format("仿真[%s]主线程逻辑执行异常,仿真停止运行", this.id), e);
@ -190,7 +195,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
* @param job 仿真逻辑 * @param job 仿真逻辑
* @param rate 执行频率单位ms * @param rate 执行频率单位ms
*/ */
public void addJob(String name, SimulationJob job, int rate) { public void addJob(String name, Runnable job, int rate) {
if (null == name) { if (null == name) {
throw new IllegalArgumentException("name can't be null"); throw new IllegalArgumentException("name can't be null");
} }
@ -207,7 +212,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
* @param job 仿真逻辑 * @param job 仿真逻辑
* @param rate 执行频率单位ms * @param rate 执行频率单位ms
*/ */
public void addFixedRateJob(String name, SimulationJob job, int rate) { public void addFixedRateJob(String name, Runnable job, int rate) {
if (null == name) { if (null == name) {
throw new IllegalArgumentException("name can't be null"); throw new IllegalArgumentException("name can't be null");
} }
@ -223,9 +228,9 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
* @param job * @param job
* @param delay * @param delay
*/ */
public void addDelayExecuteJob(SimulationJob job, long delay) { public void addDelayExecuteJob(Runnable job, long delay) {
SimulationDelayJob delayJob = new SimulationDelayJob(this, job, delay); SimulationDelayJob delayJob = new SimulationDelayJob(this, job, delay);
this.jobMap.put(delayJob.getId(), delayJob); this.jobMap.put(delayJob.getName(), delayJob);
} }
/** /**

View File

@ -4,48 +4,30 @@ import club.joylink.rtss.simulation.Simulation;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@Slf4j @Slf4j
@Getter @Getter
public final class SimulationDelayJob implements SimulationJob { public final class SimulationDelayJob extends SimulationJob {
private static final AtomicLong ID_SEED = new AtomicLong(0); private static final AtomicLong ID_SEED = new AtomicLong(0);
private Simulation simulation;
private String id;
/**
* 运行逻辑
*/
private SimulationJob job;
/**
* 执行时间
*/
private LocalDateTime time;
/** /**
* *
* @param simulation * @param simulation
* @param job * @param job
* @param delay - 单位毫秒 * @param delay - 单位毫秒
*/ */
public SimulationDelayJob(Simulation simulation, SimulationJob job, long delay) { public SimulationDelayJob(Simulation simulation, Runnable job, long delay) {
this.simulation = simulation; super(simulation, generateId(), job, simulation.getSystemTime().plusNanos(TimeUnit.MILLISECONDS.toNanos(delay)));
this.id = generateId();
this.job = job;
this.time = simulation.getSystemTime().plusNanos(TimeUnit.MILLISECONDS.toNanos(delay));
} }
public static String generateId() { private static String generateId() {
return String.valueOf(ID_SEED.incrementAndGet()); return String.valueOf(ID_SEED.incrementAndGet());
} }
@Override @Override
public void run() { public void afterRun() {
if (simulation.getSystemTime().compareTo(this.time) >= 0) { simulation.removeJob(name);
this.job.run();
simulation.removeJob(getId());
}
} }
} }

View File

@ -3,15 +3,26 @@ package club.joylink.rtss.simulation.job;
import club.joylink.rtss.simulation.Simulation; import club.joylink.rtss.simulation.Simulation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
public final class SimulationFixedJob extends SimulationScheduledJob { public final class SimulationFixedJob extends SimulationScheduledJob {
public SimulationFixedJob(Simulation simulation, String name, SimulationJob job, int rate) { public SimulationFixedJob(Simulation simulation, String name, Runnable job, int rate) {
super(simulation, name, job, rate); super(simulation, name, job, rate);
} }
@Override @Override
public void run() { public void afterRun() {
super.doRun((rate, speed) -> rate * speed); LocalDateTime systemTime = simulation.getSystemTime();
// 实际运行间隔单位ns
long runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) * simulation.getSpeed();
// 弥补非整数倍的情况
long l = Duration.between(this.runtime, systemTime).toNanos();
long l1 = l % runPeriod;
long add = runPeriod - l1;
this.runtime = systemTime.plusNanos(add);
} }
} }

View File

@ -1,6 +1,32 @@
package club.joylink.rtss.simulation.job; package club.joylink.rtss.simulation.job;
public interface SimulationJob { import club.joylink.rtss.simulation.Simulation;
import lombok.Getter;
void run(); import java.time.LocalDateTime;
@Getter
public abstract class SimulationJob {
Simulation simulation;
public String name;
/**
* 运行逻辑
*/
public Runnable job;
/**
* 执行时间
*/
public LocalDateTime runtime;
public SimulationJob(Simulation simulation, String name, Runnable job, LocalDateTime runtime) {
if (null == job) {
throw new IllegalArgumentException("job must not be null");
}
this.simulation = simulation;
this.name = name;
this.job = job;
this.runtime = runtime;
}
public abstract void afterRun();
} }

View File

@ -6,69 +6,24 @@ import lombok.extern.slf4j.Slf4j;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
@Slf4j @Slf4j
public class SimulationScheduledJob implements SimulationJob { public class SimulationScheduledJob extends SimulationJob {
Simulation simulation;
private String name;
/**
* 运行逻辑
*/
private SimulationJob job;
/** /**
* 原始频率单位ms * 原始频率单位ms
*/ */
final int rate; final int rate;
LocalDateTime nextRunTime; // 下次需要执行的时刻后续基于性能考虑可换为long类型 public SimulationScheduledJob(Simulation simulation, String name, Runnable job, int rate) {
super(simulation, name, job, simulation.getSystemTime());
public SimulationScheduledJob(Simulation simulation, String name, SimulationJob job, int rate) {
if (null == job) {
throw new IllegalArgumentException("job must not be null");
}
if (rate <= 0) { if (rate <= 0) {
throw new IllegalArgumentException("rate must bigger than 0"); throw new IllegalArgumentException("rate must bigger than 0");
} }
this.simulation = simulation;
this.name = name;
this.job = job;
this.rate = rate; this.rate = rate;
} }
public static final long TIMEOUT_NANO = TimeUnit.MILLISECONDS.toNanos(5); public static final long TIMEOUT_NANO = TimeUnit.MILLISECONDS.toNanos(5);
@Override
public void run() {
doRun((rate, speed) -> rate);
}
void doRun(BiFunction<Long, Integer, Long> consumer) {
LocalDateTime systemTime = simulation.getSystemTime();
if (this.nextRunTime == null || systemTime.compareTo(this.nextRunTime) >= 0) {
long start = System.nanoTime();
this.job.run();
long used = System.nanoTime() - start;
if (used > TIMEOUT_NANO) {
log.warn(String.format("仿真任务[%s]执行耗时[%sms]超过[%sms],请检查并调优",
this.name, TimeUnit.NANOSECONDS.toMillis(used), TimeUnit.NANOSECONDS.toMillis(TIMEOUT_NANO)));
}
// 实际运行间隔单位ns
Long runPeriod = consumer.apply(TimeUnit.MILLISECONDS.toNanos(this.rate), simulation.getSpeed());
if (this.nextRunTime != null) {
// 弥补非整数倍的情况
long l = Duration.between(this.nextRunTime, systemTime).toNanos();
long l1 = l % runPeriod;
long add = runPeriod - l1;
this.nextRunTime = systemTime.plusNanos(add);
} else {
this.nextRunTime = systemTime.plusNanos(runPeriod);
}
}
}
public String getName() {
return name;
}
/** /**
* *
@ -78,4 +33,16 @@ public class SimulationScheduledJob implements SimulationJob {
public int calculateRunTimes(long interval) { public int calculateRunTimes(long interval) {
return (int) (interval / TimeUnit.MILLISECONDS.toNanos(this.rate)); return (int) (interval / TimeUnit.MILLISECONDS.toNanos(this.rate));
} }
@Override
public void afterRun() {
LocalDateTime systemTime = simulation.getSystemTime();
// 实际运行间隔单位ns
long runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate);
// 弥补非整数倍的情况
long l = Duration.between(this.runtime, systemTime).toNanos();
long l1 = l % runPeriod;
long add = runPeriod - l1;
this.runtime = systemTime.plusNanos(add);
}
} }