Using synchronized / locks in future code

We are building a web application with Scala, a playback platform, and MongoDB (with ReactiveMongo as our driver). The architecture of the application is not blocked from end to end.

In some parts of our code, we need to access some unsafe libraries, such as Scala parser combinators, reflection Scala, etc. We are currently including such calls in synchronized blocks. I have two questions:

  • Are there any errors to look for when using synchronized with future-y code?
  • Is it better to use locks (e.g. ReentrantLock ) rather than synchronized in terms of performance and usability?
+6
source share
4 answers

This is an old question)) see here using-actors-instead-of-synchronized . In short, it would be better to use actors instead of locks:

 class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) โ‡’ log.info("Hello " + who) } } 

only one message will be processed at any given time, so you can put any safe code without a thread, not log.info, everything will work fine. BTW using the request template, you can easily integrate your members into existing code that requires futures.

+8
source

For me, the main problem that you will encounter is that any call to a synchronized or blocked section of code can block and thus paralyze execution context threads. To avoid this problem, you can bind any call to a potentially blocking method using scala.concurrent.blocking :

 import scala.concurrent._ import ExecutionContext.Implicits.global def synchronizedMethod(s: String) = synchronized{ s.size } val f = future{ println("Hello") val i = blocking{ //Adjust the execution context behavior synchronizedMethod("Hello") } println(i) i } 

Of course, it might be better to consider alternatives, such as streaming local variables or transferring a call to serial code inside an actor.

Finally, I suggest using synchronization instead of locks. For most applications (especially if critical sections are huge) the performance difference is not noticeable.

+3
source

The examples you mentioned, such as reflection and parsing, should be reasonably unchanged, and you do not need to block, but if you intend to use locks, then a synchronized block will be executed. I do not think that there is a big difference in performance between using synchronization and locking.

+2
source

Well, I think the easiest and safest way is (if at all possible) from a Stream Limit . that is, each thread creates its own instance of combinatorial combinators, etc., and then uses it.

And if you need any kind of synchronization (which should be avoided, since it will be a killer under traffic), synchornized or ReentrantLock will give almost the same performance. It again depends on what objects need to be protected from any locks, etc. In a web application, it is not recommended if it is absolutely necessary.

+2
source

Source: https://habr.com/ru/post/950152/


All Articles