我之前一直用java语言编程,最近一年用python fastapi和nodejs nestjs开发了一些项目,站在java程序员的角度谈谈异步编程和同步编程的区别,主要在两方面1.处理请求 2.编程习惯
同步编程
习惯了java开发,觉得同步编程易于理解,在主线程执行期间,如果想同时执行另一个任务,就新建线程去做,并通过callable get方法、线程阀、中断等办法得知线程执行结果。
以下面代码为例,我们想让第二件事和第三件事同时进行,用新线程执行第二件事,但想获得第二件事结果要在主线程堵塞等待get。
我们知道tomcat默认用150个线程,每个线程处理一个请求,堆积的请求会进入队列。在futureTask.get()时,当前处理请求的线程被堵塞,但不影响tomcat的剩余149处理请求,所以tomcat依然能处理新请求。
System.out.println("第一件事");
FutureTask futureTask = new FutureTask<>((Callable) () -> {
System.out.println("第二件事");
return 1;
});
Thread thread = new Thread(futureTask);
thread.start();
System.out.println("第三件事");
Object o = futureTask.get();
System.out.println("第二件事结果"+o);
异步编程
nodejs
首先nodejs编程里所有方法都是异步的,这点跟java不一样。
nodejs是单线程这个说法,说的是计算线程只有1个,但io线程有多个,如何处理请求涉及事件eventloop。
在场景web场景中,收到一个请求后,计算线程执行几行代码就该去查数据库,查数据库io操作不需要cpu,这个io操作及回调函数就被注册到事件上,io线程无限循环直到检查到哪些注册的io事件完成了,就调用其回调函数。
以下代码完成了上面java代码相同的事,第二件事用异步执行,想获取第二件事的结果只能阻塞等待用await,await阻塞就是注册了事件,等事件完成就会回调到原来位置,继续执行console.log("第二件事结果"+ result);。 这里与tomcat不同的是,执行线程只有1个,await阻塞并没有阻塞到计算线程,计算线程可以继续执行其他不阻塞的代码,直到等待事件回调。
async function a(){
console.log("第一件事")
const promise = b();
console.log("第三件事")
const result = await promise;
console.log("第二件事结果"+ result);
}
async function b(){
console.log("第二件事");
return 1;
}
a();
python fastapi
fastapi的异步处理请求过程跟node一样,只是fastapi同时支持异步和同步,当接口方法加了async时,走异步处理流程,当不加async时请求由线程池进行处理、跟tomcat类似!
参考这篇文章python - uvicorn 如何调节线程池大小 - SegmentFault 思否
这篇文章也很好的体现了fastapi异步和同步编程的区别FastAPI到底用不用async?_fastapi async-CSDN博客