随着机器学习技术的不断发展,人工智能已经开始渗透到各个领域。其中,最引人注目的之一便是 AI 辅助编程工具。在这个领域里,Github Copilot 无疑是一颗闪耀的明星,它可以推荐代码片段、自动生成代码,并提供代码补全和建议等功能。Github Copilot 以插件的方式集成到IDA中,如果你的IDE找不到或无法安装这个插件,请升级软件版本。
目录
前年为应对项目中调用的一个接口限流问题,简单写了一个单机版的滑动窗口计数器。今天想让 Copilot 写一个,输入类名称后,它向我推荐的代码片段,竟然我和之前编写的一模一样。以下分别是以前写的代码片段(完整代码在文末),和 Copilot 推荐的代码片段。
自己以前写的代码片段
Copilot 推荐的代码片段
更有趣的是,Copilot 可以不断地学习和改进。细心的读者可能已经发现,前面两幅图中的代码有一点差异,是因为我对自己的代码进行了优化,去掉了第27行的 if。Copilot 也注意到了这一点,并更新自己的模型数据,不久后当我让 Copilot 重新推荐这个代码,并且即使我对自己的代码撤销了该优化,Copilot 仍向我推荐优化后的代码。
最后的main()方法,Copilot 没参考我以前的代码,只根据上下文生成,相比我自己写的要简单些。
完整代码
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* 滑动窗口计数器
*/
public class SlidingWindow {
//滑动窗口元素数组
private final WindowElement[] windowElements;
//窗口长度
private final int windowSize;
//窗口期
private final long windowDuration;
//窗口精度
private final long windowAccuracy;
//时间戳
private long ctm;
//滑动窗口元素
private class WindowElement {
public AtomicLong num = new AtomicLong(0);
public long ts = 0;
public long incrAndGet() {
synchronized (this) {
if (ts < ctm - windowDuration) {
num.set(1);
ts = ctm;
return 1;
}
}
return num.incrementAndGet();
}
}
/**
* 创建一个滑动窗口计数器
* @param duration
* @param accuracy
*/
public SlidingWindow(Duration duration, Duration accuracy) {
windowDuration = duration.toMillis();
windowAccuracy = accuracy.toMillis();
//窗口长度+1,确保窗口元素过期才会被覆盖
windowSize = (int) Math.ceil(1.0 * duration.toMillis() / accuracy.toMillis()) + 1;
windowElements = new WindowElement[windowSize];
for (int i = 0; i < windowSize; i++) {
windowElements[i] = new WindowElement();
}
}
/**
* 计数+1
* @return
*/
public long increment() {
ctm = System.currentTimeMillis();
int index = (int) ((ctm / windowAccuracy) % windowSize);
return windowElements[index].incrAndGet();
}
/**
* 计数+1并返回计数总和
* @return
*/
public long incrementAndGet() {
long sum = increment();
if (windowSize == 1) {
return sum;
} else {
return Arrays.stream(windowElements).filter(e -> e.ts >= ctm - windowDuration).mapToLong(e -> e.num.get()).sum();
}
}
/**
* 返回窗口中所有计数总和
* @return
*/
public long getSum() {
ctm = System.currentTimeMillis();
return Arrays.stream(windowElements).filter(e -> e.ts >= ctm - windowDuration).mapToLong(e -> e.num.get()).sum();
}
public static void main(String[] args) {
SlidingWindow window = new SlidingWindow(Duration.ofMillis(500), Duration.ofMillis(100));
Random rand = new Random(System.currentTimeMillis());
//创建一个线程,每50ms执行一次,输出当前窗口计数总和
Thread thread = new Thread(() -> {
while (true) {
System.out.println(LocalDateTime.now() + " sum: " + window.getSum());
try {
Thread.sleep(50);
} catch (InterruptedException e) {
break;
}
}
});
thread.start();
//创建5个线程,每个线程随机休眠0~100ms,随机执行+1操作
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
for (int t = 0; t < 5; t++) {
executor.execute(() -> {
String threadName = Thread.currentThread().getName();
for (int i = 0; i < 50; i++) {
String out = LocalDateTime.now() + " [" + threadName + "]";
if (rand.nextBoolean()) {
window.increment();
System.out.println(out + " +1");
}
try {
Thread.sleep(rand.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//关闭线程池
executor.shutdown();
//等待线程池中所有线程执行完毕
try {
executor.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
//通知线程thread退出
thread.interrupt();
}
}