title: Sending parallel requests Erlang
body: <p>I am implementing a Twitter-like application in Erlang. I have both its distributed and non-distributed implementations. I am doing a benchmark but it seems I cannot find a way to send parallel requests to each user process for the distributed implementation. I am using a lists:foreach function to send "get tweets" to a list of client processes.My understanding is that the lists:foreach function steps into each element of the list one at a time realizing a sequential behavior which ultimately makes my distributed implementation result in an equal execution time with the non-distributed implementation. Is it possible to send the "get tweets" requests to different client processes all at once? This to me seems like a rather specific case and it has been difficult to search for a solution inside and outside StackOverflow.</p>
  
  <pre><code>test_get_tweets_Bench() -&gt;
  {ServerPid, UserInfos} = initializeForBench_server(),
  run_benchmark("timeline",
      fun () -&gt;
          lists:foreach(fun (_) -&gt;
              UserChoice = pick_random(UserInfos),
              server:get_tweets(element(2, UserChoice), element(1, UserChoice), 1)
          end,
          lists:seq(1, 10000))
      end,
      30).
  
  pick_random(List) -&gt;
  lists:nth(rand:uniform(length(List)), List).
  </code></pre>
  
  <p>userinfos is a list of the following form: [{userId,client_process},...]</p>
  
  <p>After trying rpc:pmap instead of the lists:foreach, my benchmark has become approximately 3 times slower. The changes are as follows:</p>
  
  <pre><code>test_get_tweets_Bench2() -&gt;
  {ServerPid, UserInfos} = initializeForBench_server(),
  run_benchmark("get_tweets 2",
      fun () -&gt;
          rpc:pmap({?MODULE,do_apply},
                   [fun (_) -&gt;
              UserChoice = pick_random(UserInfos),
              server:get_tweets(element(2, UserChoice), element(1, UserChoice), 1)
          end],
                      lists:seq(1, 10000))
      end,
      30).
  
  
  pick_random(List) -&gt;
      lists:nth(rand:uniform(length(List)), List).
  
  do_apply(X,F)-&gt;
      F(X).
  </code></pre>
  
  <p>I thought rpc:pmap would make my benchmark faster as it would send the get_tweet requests in parallel. </p>
  
  <p>Below is my server module which is the API between my benchmark and my Twitter-like application. The API sends the requests from my benchmark to my Twitter-like application.</p>
  
  <pre><code>    %% This module provides the protocol that is used to interact with an
  %% implementation of a microblogging service.
  %%
  %% The interface is design to be synchrounous: it waits for the reply of the
  %% system.
  %%
  %% This module defines the public API that is supposed to be used for
  %% experiments. The semantics of the API here should remain unchanged.
  -module(server).
  
  -export([register_user/1,
           subscribe/3,
           get_timeline/3,
           get_tweets/3,
           tweet/3]).
  
  %%
  %% Server API
  %%
  
  % Register a new user. Returns its id and a pid that should be used for
  % subsequent requests by this client.
  -spec register_user(pid()) -&gt; {integer(), pid()}.
  register_user(ServerPid) -&gt;
      ServerPid ! {self(), register_user},
      receive
          {ResponsePid, registered_user, UserId} -&gt; {UserId, ResponsePid}
      end.
  
  % Subscribe/follow another user.
  -spec subscribe(pid(), integer(), integer()) -&gt; ok.
  subscribe(ServerPid, UserId, UserIdToSubscribeTo) -&gt;
      ServerPid ! {self(), subscribe, UserId, UserIdToSubscribeTo},
      receive
          {_ResponsePid, subscribed, UserId, UserIdToSubscribeTo} -&gt; ok
      end.
  
  % Request a page of the timeline of a particular user.
  % Request results can be 'paginated' to reduce the amount of data to be sent in
  % a single response. This is up to the server.
  -spec get_timeline(pid(), integer(), integer()) -&gt; [{tweet, integer(), erlang:timestamp(), string()}].
  get_timeline(ServerPid, UserId, Page) -&gt;
      ServerPid ! {self(), get_timeline, UserId, Page},
      receive
          {_ResponsePid, timeline, UserId, Page, Timeline} -&gt;
              Timeline
      end.
  
  % Request a page of tweets of a particular user.
  % Request results can be 'paginated' to reduce the amount of data to be sent in
  % a single response. This is up to the server.
  -spec get_tweets(pid(), integer(), integer()) -&gt; [{tweet, integer(), erlang:timestamp(), string()}].
  get_tweets(ServerPid, UserId, Page) -&gt;
      ServerPid ! {self(), get_tweets, UserId, Page},
      receive
          {_ResponsePid, tweets, UserId, Page, Tweets} -&gt;
              Tweets
      end.
  
  % Submit a tweet for a user.
  % (Authorization/security are not regarded in any way.)
  -spec tweet(pid(), integer(), string()) -&gt; erlang:timestamp(). 
  tweet(ServerPid, UserId, Tweet) -&gt;
      ServerPid ! {self(), tweet, UserId, Tweet},
      receive
          {_ResponsePid, tweet_accepted, UserId, Timestamp} -&gt;
              Timestamp
      end.
  </code></pre>