No matter what programming language you’re using, sometimes you get itch to map a whole collection to another. Usually, you do things like:
or in C#:
or like in Python:
The main problem with above codes is that when the size of the collection grows, or the mapping itself becomes more complex, this operation will be very time-take. And that is because those codes are running in one thread.
Since all the items in the collection are mapped in the same way, why don’t we just put them onto threads and let them to be done seperatly?
Go Parallel
Parallel operations on collections is very easy in popular languages. The operation like this in most language will allow system to distribute thread resource according to the current status of CPU, and how much the task is, which could be extremely overwhelming if we write it our own.
usecase: To make it more practical, let’s say we want to download all the images based on a list, which contains 10000 urls of those images.
C#
To download these images, it could be a little complex in C#. C# has a foreach key word used to make list traversal like this:
to do that in parallel way, we use the parallel version of foreach, like this:
One thing you should be careful about is that in C# you can not map collections directly. You will have to put all the items in a parallel version of list, which is ConcurrentBag here, and it is thread safe. You can refer to another way by using ParallelLoopResult.
Python
Things could be even more easier in Python:
Please make sure you have imported the right library of pool.
scala
In scala, it is super easy to do the same thing, and you literally only one line to do that:
And done!
Of course you can define your own function to modify the string, but be sure this function is thread safe.
Spray is an elegant Framework in many ways. Here is my opinion on how to arrange your controllers(actions) in your projects, so that you can easily maintain them and test them.
Project structure
Controllers
You will find that I didn’t use class to extend Actor. I only use trait in these files.
Routes
Here is your route actor, which will combine all the controller traits.
Boot
This part is like Global in Play framework, used to start your application. We launch our route actor here.
Benefits
I believe this arrangement fits most cases.
Most people would like request handler to be separated in several files, grouping the controllers according to the related features. If people want to change anything or add anything, they can easily locate the place.
It’s clean. There will be no association with the Akka system in the middle of your real logic.
You might have noticed that since we use trait to build controllers, we can test our controllers without getting hands dirty with Akka.
Filter is a very useful concept in scala version of Play Framework.
It can allow you to do some general process to the requests before and after they are passed to controller,
which also allows you to get access to the context of requests before and after processed by controller.
However, the Filter for Java version is not, well, so useful.
You can compare Filter of these two kinds in the Doc.
Luckily, PlayFramework for Java is actually a wrapper on the scala’s PlayFramework.
So there is still a way to use scala version’s Filter in Java’s PlayFramework.
I will show how to achieve this by trying use Filter to record the process time of requests.
To use scala’s filter in Java’s PlayFramework, we need first to wrap it:
Note that interacting with scala library in Java is not really clean.
Then we could use this wrapped filter in our code:
As you can see, you can access to the context before request is processed in RecordProcessTimeFilter.apply().
You can get the time before request is processed.
And you can access to the context after request is processed within the block under return next.apply(rh).map(new AbstractFunction1<Result, Result>(){}.
Note you can only access to the variable start you stored via an AbstractFunction0 in the context when request is processed.
There are many other use cases for Filter:
Modify the http headers in the response after request is processed for all request to solve Cors problems.
Check and modify Content-Type in the request before the request is processed.
In build.sbt for both your Play API and akka actor program, add akka’s remoting lib, because this is not included in akka’s main lib.
```
(Re)Config akka
For API
For Play API, change the default akka settings in your conf/application.conf like following:
If there is no akka object in your config file, you could just add above to the config file.
For Actor
Almost do the same thing as you did in API in your src/main/resources/application.conf.
Then apply the settings in your code:
Note The provider shown above changes over versions of akka, check your version carefully and choose the right provider.
Program
API
I use Play in Java for this example. For Scala, see this.
In your controller(action), connect your remote actor using:
The main point here is that if you use ask pattern in your code, you have to wrap your result into Promise.
Actor
Actor code:
Launch code:
Now, if the controller askYourActorSomething is called, it will send a message to your actor, which is specified by your path. Then the actor receives this message and send a String back to the API controller, which consequently cause API return “worked!”.
There is a one more thing
If you are gonna use remote actor in Play application in Production, especially in distributed environment, things are going to be a little bit tough.
Firewall
This will cause it impossible to API and Actor program access to each other.
If you are using EC2, this could be solved by setting security groups. You must make sure the API and Actor program is in each other’s group’s inbound.
Pass path to the API
It seems very easy in the first sight, you can just put the actor path in the a database table by
overriding actor’s preStart method. Programatically, the API will never know the remote actor it is asking for is still working or already dead. Even if you change the record in your table when the actor is not accessible any more by overriding the postStop of Actor, this method can hardly be called in real situation.