问题引入
项目里需要用到 问题生成大模型来生成问题,所以采用了FastAPI部署,然后对外提供API从而在后端调用,模型一次只能对一个文本进行问题生成,然而每次后端都会收到前端传来的文件,文件中包含几十上百条句子,所以每次都要请求这个API几十上百次,大模型的响应速度懂得都懂,所以在最开始每次在前端输入文件之后都需要等待几分钟甚至更久才会收到响应,这个接口几乎不可用。为了提升效率,在模型速度已经没有办法优化的情况下,只能想到要提升服务器性能。然而经费实在有限,租不起昂贵的服务器,只能采用以数量取胜的方法,租借了3台很差的服务器,然后在每台服务器上都部署了API,后端通过多线程的方式进行请求,从而实现前后端异步以及提升API的吞吐率。
然而如何最大化利用这3台服务器提供的API成了问题,因为每个服务器每次响应的速度都是不可预知的,如果把所有生成任务平均分给3台服务器,那么势必造成有些服务器已经跑完了所有任务处于空闲状态,而有些服务器仍然在加班加点,还有一堆的任务没处理完,就像牛逼的同事早早的干完活下班,而你还在加班,这个时候你肯定会想同事来帮你一起干该多好!同事不是你爹,肯定不愿意帮你干,但是服务器没有拒绝的权利,那么应该怎么充分利用呢?
解决方案
方案一:根据服务器性能按比例分配
这是最初想到的方案,3090肯定得比1060多干点活,然而这个方案有俩问题:
一、具体应该是怎么样的分配比例?难道边调用接口边盯着top调整吗?显然不现实,只能根据经验来分配比例,这种分配方式必然达不到最佳。
二、就算比例合适,由于每次模型运算速度具有不可预知性,还是会出现服务器空闲的情况。
方案二:采用生产者消费者模式
将三台服务器的API请求地址作为生产者的资料,而后端的多线程作为消费者来消费者这些API,线程每次先获取一个API,然后调用,生成完问题写入数据库之后再作为生产者将API生产出来,提供给其他线程。这样性能较高的服务器所提供的API就会更快的消费完从而更快的生产,达到最大化利用服务器性能的目的。
同时采用工具类的方式进行实现,在类中定义一个队列保存API地址,在调用不同算法时向队列中写入不同的API,从而实现解耦,在不同的集成模块都能使用这个工具类实现生产者消费者的调用方式。以下是工具类的Demo:
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.*;
//采用生产者消费者模式对部署在不同服务器上的多个api进行请求,从而提升模型响应速度
public class NewContainer {
Queue<String>urls=new LinkedList<>();
private final int MAX=3;
private int count=3;
//get方法获取api的地址
public synchronized String get(){
while (count==0){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
String url=urls.poll();
System.out.println(Thread.currentThread().getName()+"向"+url+"发送请求,生成问题");
count--;
this.notifyAll();
return url;
}
//add方法将api地址放入队列
public synchronized void add(String url){
while (count==MAX){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName()+"向"+url+"请求完毕,放入队列中");
urls.add(url);
count++;
this.notifyAll();
}
public static void main(String[] args) {
//采用线程池实现线程复用
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(10,15,60L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
NewContainer newContainer=new NewContainer();
newContainer.urls.add("url1");
newContainer.urls.add("url2");
newContainer.urls.add("url3");
Random random=new Random();
//这里的10是要处理的任务数量
for (int i = 0; i < 10; i++) {
threadPoolExecutor.execute(()->{
String url=newContainer.get();
try {
//这里用随机延迟模拟调用算法的需要的时间
Thread.sleep(random.nextInt(30000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
newContainer.add(url);
});
}
}
}
输出结果如下

文章讨论了一个项目中使用FastAPI部署的问题生成大模型,由于模型响应速度慢,对大量文本请求导致效率低下。为提高效率,采用3台低性能服务器并行处理,但面临任务分配不均的问题。提出了两种解决方案:一是按服务器性能分配任务,但比例难以精确调整;二是采用生产者消费者模式动态平衡任务,通过线程池实现线程复用,达到最大化利用服务器性能的目的。给出的Java代码示例展示了如何实现这一模式。
605

被折叠的 条评论
为什么被折叠?



