#Why is it recommended to avoid blocking I/O operations, like db calls, when using ForkJoinPool?

56 messages · Page 1 of 1 (latest)

rich bone
#

I’m using CompletableFutures and their functions and I’ve read that it’s best to avoid blocking operations for the ForkJoinPool which is what CompletableFutures use (common pool). Is it because of the work stealing approach? Would blocking operations be better fit for a fixed thread pool then or?

I’m asking because I’m making calls to a ddb and I can use either an async or sync table and I initially thought since I’m already running the entire flow asynchronously then using a sync table would suffice but this says otherwise.

grand flaxBOT
#

This post has been reserved for your question.

Hey @rich bone! Please use /close or the Close Post button above when you're finished. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

willow goblet
#

well, if you are doing a blocking operation, the thread is blocked

#

this means it cannot be used by another task

#

work-stealing allows you to use (non-blocked) threads for something else

rich bone
# willow goblet this means it cannot be used by another task

So if a thread was executing an async block of code where a non blocking async db call was made, could that thread automatically be used for another task? I read somewhere that a thread won’t actually know if the operation is blocking or not so how would this work?

willow goblet
#

work-stealing means that a thread says "I'm free now and I can execute another task"

#

simplified

#

blocking a thread means the thread doesn't do anything until some point (e.g. until the IO operation finishes or when some (fixed) time is over or when a lock is released)

rich bone
# willow goblet work-stealing means that a thread says "I'm free now and I can execute another t...

So how does this differ from a non work stealing approach like other types of thread pools.

For the example I gave if a thread from the common pool that employs work stealing made an async db call and thus did not block, are you saying it would say it’s free and look for other tasks until the future completes? If that is the case then if work stealing wasn’t being employed in say a fixed thread pool, would the thread stay on that task until it’s completed whether it’s blocking or not? Or is the point here that work stealing allows that thread to look for work on its own as opposed to being assigned work

willow goblet
#

For "normal" thread pools, you create some threads and if a thread is blocked, it cannot be used for other tasks

#

with work stealing, you can submit multiple tasks to the thread pool and while one of them is waiting for the DB operation (asynchronously), the other task can run on that thread

rich bone
#

So for normal thread pools, even if a thread calls an async db operation, it would still be blocked and that thread cannot be used for other tasks?

willow goblet
#

if the task completes, the thread can be used for other tasks

rich bone
#

the task wouldn’t be complete if it’s waiting for the future of the db call to complete right?

willow goblet
#

if you use callbacks/actually do it asynchronously, it would complete

#

or just continue working

#

asynchronous programming works like this: you say "Please run this thing (e.g. I/O) and when it's finished, execute that code"

#

and you don't wait for it to finish

#

you just continue doing your other stuff

rich bone
#

Right. Im just confused as to why in the docs it said it’s best to avoid blocking operations for common pool and I read elsewhere that common pool is better fit for CPU intensive tasks when compared to other pools. However from how you’re describing it it seems both can do other tasks if they are not blocked so i don’t really see the difference

willow goblet
#

the common pool is also used for other things

#

if you block threads from that, you take away these threads from the other tasks using tze common pool

rich bone
#

Okay that makes sense

#

So we should always try to avoid blocking when possible regardless of the pool but common pool can be used by more things and thus the effects of blocking can be more damaging.

Although we can’t always avoid blocking. For example if im making a db call and want to do something with the result it is probably the same thing to make it an async call then call .get() (if there’s no other code that can be executed in the meantime between) or to just make it a sync db call right

rich bone
willow goblet
#

but that's - kinda polluting your code

#

it's the reactive approach if you heard about that

#

you might have heard about virtual threads - you can block those as you like without any problems

#

Java majes sure the platform threads aren't actually blocked and that some other virtual threads can use them

#

but that's still in Preview

rich bone
#

Yeah I’ve been using the callbacks quite a bit

#

Right I think I heard of those and that they want to incorporate them into common pool or something in new version but I’m using Jdk 8

willow goblet
#

I think work szealing allows you to write code that's still somehow synchronous but not sure

rich bone
#

Interesting, not sure how that would look tbh.

willow goblet
willow goblet
rich bone
willow goblet
#

but I didn't really look into work stealing yet

rich bone
#

Yeah I’ve taken a look at that it’s good. It actually said in there to try and avoid blocking

rich bone
#

I feel I am going too deep into this. I am actually carrying out quite a simple task that needs to be run completely asynchronously to start, as a way of running in the background or shadow testing without affecting the existing main flow of the program. All the flow is doing is just making calls to ddb and recording some metrics but i wanted to get a better idea of the right approach. If I have some more implementation specific questions regarding completablefutures should I ask here or a new question ? Thanks for all the help and knowledge sharing btw I appreciate it

rich bone
willow goblet
#

if you use a thread pool and there are many tasks submitted to it/want to avoid blocking, you could write it asynchronously

rich bone
# willow goblet if you use a thread pool and there are many tasks submitted to it/want to avoid ...

Well AWS ddb async client has its own thread pool: “By default, each asynchronous client creates a threadpool based on the number of processors and manages the tasks in a queue within the ExecutorService”. So wouldn’t or be best to just use that even if it’s within a separate thread or does it not matter much if the calls are light weight and there’s not much other stuff going on in that thread. Also I was using common pool

willow goblet
#

well, anything in xour application could use the common pool

#

if you are blocking the common pool, you might slow down other things in your application

rich bone
#

So i will try to use the async client, although there is something that is making it hard for me, namely a checked exception, but ill make another question about that. Thanks for all your help Daniel! I've made an implementation/design specific question #1084596512937484308 message if you are interested. I'll close this question for now

grand flaxBOT
grand flaxBOT