in reply to Re^4: Do I need to use Coro instead of threads/forks
in thread Do I need to use Coro instead of threads/forks

Or can i try one of your excellent suggestion here Re: Why Coro?. using OS threads for each vendor and then use coros inside them to fulfill new requirement.

For just 10 threads, mixing Coro/threads would be overkill. (It has also never been confirmed to me that Coro is thread safe.) Personally, I'd stick to the known simplicity of threads. Also, if you go the mixed architecture route, you may find yourself out in the cold as far as support is concerned. I'm pretty sure that the Coro author doesn't do threads; and I don't do Coro; so you'd be on your own if things go tits-up.

Also, unless your vendors are unusually tolerant; if you going hitting their websites with multiple concurrent requests, you are likely to get your accounts suspended. You may even find that hitting them with large numbers of requests serially with be frowned upon unless you put some delays between each request.

My advice is: stick to one thread per vendor and a simple serial loop over the request to each vendor. Once you have that working, you can benchmark and look for opportunities to improve performance if it proves necessary.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
  • Comment on Re^5: Do I need to use Coro instead of threads/forks

Replies are listed 'Best First'.
Re^6: Do I need to use Coro instead of threads/forks
by mohan2monks (Beadle) on Sep 30, 2014 at 11:42 UTC

    Thanks for your support.
    I have tried both approaches with OS threads and Coro.
    As above started one OS thread per vendor (used limited functionality for 3 vendors) and serial loop for inside calls per thread.
    With Coro started 3 threads and each doing inside calls asynchronously.
    Even though Coro seems to fetch all results in parallel overall response time for Coro is much higher.
    Is this because Coro is running in a single process while OS threads has 4.
    I thought as my scripts waits for IO for larger amount of time compared to actually process the received data Coro should win.

    I have logged request and response times for SOAP calls for both as below.

    Using OS threads total time 13 seconds Start time Tue Sep 30 15:29:00 2014 Request 859 sent time Tue Sep 30 15:29:01 2014 #thread 1 Request 532 sent time Tue Sep 30 15:29:01 2014 #thread2 Request 906 sent time Tue Sep 30 15:29:02 2014 #thread3 Response 859 receive time Tue Sep 30 15:29:03 2014 #thread 1 respon +se Request 155 sent time Tue Sep 30 15:29:03 2014 Response 532 receive time Tue Sep 30 15:29:03 2014 #thread 2 respon +se Request 232 sent time Tue Sep 30 15:29:04 2014 Response 906 receive time Tue Sep 30 15:29:04 2014 #thread 3 respon +se Request 870 sent time Tue Sep 30 15:29:04 2014 Response 870 receive time Tue Sep 30 15:29:06 2014 Request 570 sent time Tue Sep 30 15:29:06 2014 Response 232 receive time Tue Sep 30 15:29:07 2014 Response 155 receive time Tue Sep 30 15:29:07 2014 Request 461 sent time Tue Sep 30 15:29:07 2014 Response 570 receive time Tue Sep 30 15:29:09 2014 Request 585 sent time Tue Sep 30 15:29:09 2014 Response 585 receive time Tue Sep 30 15:29:10 2014 Response 461 receive time Tue Sep 30 15:29:10 2014 Request 479 sent time Tue Sep 30 15:29:10 2014 Response 479 receive time Tue Sep 30 15:29:13 2014 Using Coro's total time 31 sec Coros Start time Tue Sep 30 16:03:53 2014 Request 812 sent time Tue Sep 30 16:03:53 2014 #thread1 Request 923 sent time Tue Sep 30 16:03:54 2014 #thread2 Request 942 sent time Tue Sep 30 16:03:57 2014 #thread3 Response 812 receive time Tue Sep 30 16:03:59 2014 #thread1 respons +e Response 923 receive time Tue Sep 30 16:04:00 2014 #thread2 respons +e Response 942 receive time Tue Sep 30 16:04:01 2014 #thread3 respons +e # individual threads starting sub threads async Request 312 sent time Tue Sep 30 16:04:01 2014 Request 607 sent time Tue Sep 30 16:04:02 2014 Request 578 sent time Tue Sep 30 16:04:03 2014 Request 675 sent time Tue Sep 30 16:04:04 2014 Request 310 sent time Tue Sep 30 16:04:05 2014 Request 720 sent time Tue Sep 30 16:04:06 2014 Request 502 sent time Tue Sep 30 16:04:07 2014 Request 867 sent time Tue Sep 30 16:04:08 2014 Response 312 receive time Tue Sep 30 16:04:11 2014 Response 607 receive time Tue Sep 30 16:04:13 2014 Response 578 receive time Tue Sep 30 16:04:16 2014 Response 675 receive time Tue Sep 30 16:04:18 2014 Response 310 receive time Tue Sep 30 16:04:21 2014 Response 720 receive time Tue Sep 30 16:04:22 2014 Response 502 receive time Tue Sep 30 16:04:24 2014 Response 867 receive time Tue Sep 30 16:04:26 2014

    May be i am better of with BrowserUK suggested approach or have not understood Coro correctly.
    please suggest.

      First I'd say that without you publish the code behind those two run traces, you'll not get anyone very exited about the comparison. It could well be that you've some fundamental error in your coding of one or both solutions.

      That said. I doubt the comparison will come as any great surprise to anyone who has though about it.

      Think of it like a small supermarket that has 4 checkouts. On one day, there are also 4 checkout operators. On another day, all 4 checkouts are operating but only one operator flitting between the tills on demand.

      Using cooperative multitasking (alone*) on a machine with multiple cores will always leave 75% of your potential throughput untapped.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        I used the same code posted above only changing syntax needed to create Coro and OS threads.
        This is not working code but the only difference is my actual code has functions that connect to vendor api.

        OS thread code
        #!/usr/bin/perl $|=1; print "Start time ".(localtime). "\n"; use strict; use threads; use CGI qw(:standard); use XML::Simple; use JSON qw(encode_json); use MIME::Base64 qw(encode_base64); use DBI; use SOAP::Lite; use POSIX qw(ceil); use Data::Dumper; use CHI; $XML::Simple::PREFERRED_PARSER='XML::Parser'; $SOAP::Constants::DO_NOT_USE_CHARSET = 1; my (@req,@odata,@errdet)=(); my %threads=(); foreach my $vnd (@req){ #$threads{$vnd}=threads->create({ 'context' => 'list', 'exit' +=> 'thread_only' },\&startthread,$vnd,$SCH); $threads{$vnd}=async{&startthread($vnd,$SCH) }; } cede; foreach my $vnd (keys %threads) { my($err,$data) =$threads{$vnd}->join(); if ($err eq 'N') { push @odata,@{$data}; } }elseif($err eq 'Y'){ push @errdet,$data; }elsif($threads{$vnd}->error) # with threads it was useful, { push @errdet,{ Vnd=>$vnd, ErrorCode=>26,ErrorMsg=>$threads +{$vnd}->error}; } } sub startthread { my ($vendor,$SCH)=@_; my($err,$data) =(); require './'.$vendor.'functions.pl"; #load vendor specific code ($err,$data)=&getvendordata($SCH); return($err,$data); } #vendor functions has somewhat code like this besides functions specif +ic to each vendor api #fetch data serially in a loop waiting for each call to finish before +going on next sub getvendordata { my $SCH=shift; #perform vendor specific tasks mostly SOAP::Lite calls to api #Has to perform multiple calls some of them depend on output of pr +evious calls #Also have to make simultaneous calls which may not be related to +each other can be done parallelly. #e.g. first call to api returns a list of products subsequent call +s to fetch details. #If i start threads/forks again here most of the time program cras +hes :( my ($err,@data)=(); my @products=getproduects(); #Maybe i can start coro routines here to get all listed detail +s simultaneously foreach my $product (@products) { #fetch product details over api push @data,$product->getdetails; } return ($err,\@data); }

        Coro Code

        use strict; use Coro; #use Coro::LWP; use LWP::Protocol::AnyEvent::http; use CGI qw(:standard); use XML::Simple; use JSON qw(encode_json); use MIME::Base64 qw(encode_base64); use DBI; use POSIX qw(ceil); use Data::Dumper; use CHI; use SOAP::Lite; use SOAP::Transport::HTTP; $XML::Simple::PREFERRED_PARSER='XML::Parser'; $SOAP::Constants::DO_NOT_USE_CHARSET = 1; my (@req,@odata,@errdet)=(); my %threads=(); foreach my $vnd (@req){ #$threads{$vnd}=threads->create({ 'context' => 'list', 'exit' +=> 'thread_only' },\&startthread,$vnd,$SCH); $threads{$vnd}=async{&startthread($vnd,$SCH) }; } cede; foreach my $vnd (keys %threads) { my($err,$data) =$threads{$vnd}->join(); if ($err eq 'N') { push @odata,@{$data}; } }elseif($err eq 'Y'){ push @errdet,$data; }elsif($threads{$vnd}->error) # with threads it was useful, { push @errdet,{ Vnd=>$vnd, ErrorCode=>26,ErrorMsg=>$threads +{$vnd}->error}; } } sub startthread { my ($vendor,$SCH)=@_; my($err,$data) =(); require './'.$vendor.'functions.pl"; #load vendor specific code ($err,$data)=&getvendordata($SCH); return($err,$data); } #vendor functions has somewhat code like this besides functions specif +ic to each vendor api #fetch data asyncronously with coro async for each product sub getvendordata { my $SCH=shift; #perform vendor specific tasks mostly SOAP::Lite calls to api #Has to perform multiple calls some of them depend on output of pr +evious calls #Also have to make simultaneous calls which may not be related to +each other can be done parallelly. #e.g. first call to api returns a list of products subsequent call +s to fetch details. #If i start threads/forks again here most of the time program cras +hes :( my ($err,@data)=(); my @products=getproduects(); #Maybe i can start coro routines here to get all listed detail +s simultaneously my @tasks=(); foreach my $product (@products) { #fetch product details over api push @tasks,async {push @data,$product->getdetails}; } foreach my $task (@ftasks) { $task->join(); } return ($err,\@data); }

        I wait for all threads to finish by joining them.