https://www.projectpro.io/article/mlops-projects-ideas/486#mcetoc_1ffp2ld4ah
10 MLOps Projects Ideas for Beginners to Practice in 2023
From a programmer's perspective blocking I/O is easier to use than nonblocking I/O. You just call the read/write function and when it returns you are done. With nonblocking I/O you need to check if you can read/write, then read/write and then check the return values. If not everything was read or written you need mechanisms to read again or to write again now or later when write can be done.
Regarding performance: nonblocking I/O in one thread is not faster than blocking I/O in one thread. The speed of the I/O operation is determined by the device (for example the hard disc) that is read from or written to. The speed is not determined by someone waiting for (blocking on) or not waiting for (nonblocking on) it. Also if you call a blocking I/O function then the OS can do the blocking quite effectively. If you need to do the blocking/waiting in the application you might do that nearly as good as the OS, but you might also do it worse.
So why do programmers make their life harder and implement nonblocking I/O? Because, and that is the key point, their program has more to do than only that single I/O operation. When using blocking I/O you need to wait until the blocking I/O is done. When using nonblocking I/O you can do some calculations until the blocking I/O is done. Of course during nonblocking I/O you can also trigger other I/O (blocking or nonblocking).
Another approach to nonblocking I/O is to throw in more threads with blocking I/O, but as said in the SO post that you linked threads come with a cost. That cost is higher is than the cost for (OS supported) nonblocking I/O.
If you have an application with massive I/O but only low CPU usage like a web server with lots of clients in parallel, then use a few threads with nonblocking I/O. With blocking I/O you'll end up with a lot of threads -> high costs, so use only a few threads -> requires nonblocking I/O.
If you have an application that is CPU intensive like a program that reads a file, does intensive calculations on the complete data and writes the result to file, then 99% of the time will be spent in the CPU intensive part. So create a few threads (for example one per processor) and do as much calculation in parallel. Regarding the I/O you'll probably stick to one main thread with blocking I/O because it is easier to implement and because the main thread itself has nothing to do in parallel (given that the calculations are done in the other threads).
If you have an application that is CPU intensive and I/O intensive then you'ld also use a few threads and nonblocking I/O. You could think of a web server with lots of clients and web page requests where you are doing intensive calculations in a cgi script. While waiting for I/O on on connection the program could calculate the result for another connection. Or think of a program that reads a large file and could do intensive calculations on chunks of the file (like calculating an average value or adding 1 to all values). In that case you could use nonblocking reads and while waiting for the next read to finish you could already calculate on the data that is available. If the result file is only a small condensed value (like an average) you might use blocking write for the result. If the result file is as large as the input file and is like "all values +1", then you could write back the results nonblocking and while the write is being done you are free to do calculations on the next block.
프로그래머의 관점에서 블로킹 I/O가 비블로킹 I/O보다 사용하기 쉽습니다. 단지 read/write 함수를 호출하고 반환되면 끝입니다. 비블로킹 I/O를 사용하면 읽거나 쓸 수 있는지 확인한 다음에 읽기/쓰기를 하고 반환값을 확인해야 합니다. 모든 데이터가 읽혀지거나 쓰여지지 않았다면 다시 읽거나 쓸 수 있는 메커니즘이 필요합니다.
성능에 대해서는, 하나의 스레드에서 비블로킹 I/O는 하나의 스레드에서 블로킹 I/O보다 빠르지 않습니다. I/O 작업의 속도는 읽거나 쓰는 디바이스(예를 들어 하드디스크)에 의해 결정됩니다. 속도는 대기하거나(블로킹) 대기하지 않거나(비블로킹)하는 것에 의해 결정되지 않습니다. 또한, 블로킹 I/O 함수를 호출하면 운영체제가 효과적으로 블로킹을 수행할 수 있습니다. 애플리케이션에서 블로킹/대기를 수행해야 하는 경우 운영체제만큼 잘 수행할 수도 있지만, 그렇지 않을 수도 있습니다.
그렇다면 프로그래머는 왜 비블로킹 I/O를 구현하여 자신의 삶을 더 어렵게 만들까요? 그 이유는, 그리고 이것이 핵심입니다, 그들의 프로그램은 그 단일 I/O 작업 이상을 수행하기 때문입니다. 블로킹 I/O를 사용하면 블로킹 I/O가 완료될 때까지 기다려야 합니다. 비블로킹 I/O를 사용하면 블로킹 I/O가 완료될 때까지 일부 계산을 수행할 수 있습니다. 물론, 비블로킹 I/O를 사용하면 다른 I/O(블로킹 또는 비블로킹)를 트리거할 수도 있습니다.
비블로킹 I/O에 대한 또 다른 접근 방법은 블로킹 I/O가 있는 여러 스레드를 더 많이 사용하는 것입니다. 그러나 당신이 링크한 SO post에서 말했듯이, 스레드는 비용이 따릅니다. 그 비용은 (운영체제에서 지원하는) 비블로킹 I/O의 비용보다 높습니다.
대량의 I/O가 있지만 CPU 사용량은 낮은 웹 서버와 같은 애플리케이션이 있다면 몇 개의 스레드와 비블로킹 I/O를 사용하세요. 블로킹 I/O를 사용하면 많은 스레드가 생성되어 비용이 많이 들게 됩니다. 비블로킹 I/O를 사용하면 몇 개의 스레드만 사용하면 되므로 비용이 적게 듭니다.
파일을 읽고 전체 데이터에 대해 집중적인 계산을 수행하고 결과를 파일에 쓰는 프로그램과 같은 CPU 집약적인 애플리케이션이 있다면, 대부분의 시간이 CPU 집약적인 부분에서 소요됩니다. 그래서 몇 개의 스레드(예를 들어 프로세서당 하나)를 생성하고 병렬로 많은 계산을 수행하세요. I/O에 대해서는 블로킹 I/O를 사용하는 것이 쉽기 때문에 주 스레드에서 블로킹 I/O를 사용할 것입니다. 주 스레드 자체는 병렬로 수행할 일이 없기 때문입니다.
CPU 집약적이면서 I/O 집약적인 애플리케이션이 있다면, 몇 개의 스레드와 비블로킹 I/O를 사용하세요. 많은 클라이언트와 웹 페이지 요청이 있는 웹 서버에서 CGI 스크립트에서 집중적인 계산을 수행하는 경우를 생각해 볼 수 있습니다. 연결에 대해 I/O를 기다리는 동안 프로그램은 다른 연결에 대한 결과를 계산할 수 있습니다. 또는 대용량 파일을 읽고 파일의 청크에서 집중적인 계산을 수행할 수 있는 프로그램을 생각해 볼 수 있습니다(예: 평균 값을 계산하거나 모든 값에 1을 더하는 것). 이 경우에는 비블로킹 읽기를 사용하고 다음 읽기가 완료될 때까지 기다리는 동안 사용 가능한 데이터에서 이미 계산을 수행할 수 있습니다. 결과 파일이 작은 압축 값(예: 평균)이라면 블로킹 쓰기를 사용할 수 있습니다. 입력 파일과 같은 크기의 결과 파일이고 "모든 값 +1"과 같은 형태라면 결과를 비블로킹으로 다시 쓸 수 있으며 쓰기가 완료될 때 다음 블록에서 계산을 수행할 수 있습니다.