aseipel
aseipel

Reputation: 728

Sending many parrallel WebRequests

I'm trying to simulate many concurrent users (>2000) to test a web service. Every user performs actions at a specific pre-defined time, for example:

I now want to send web request in real time at each of those times. I can tolerate a delay of at most ~2 seconds. What I was already trying without success:

a) Aggregate all times in a single list, sort it by time then iterate it:

foreach (DateTime sendTime in times) {
    while (DateTime.now < sendTime)
        Thread.Sleep(1);
    SendRequest();
}

b) Create a thread for each user, with each thread checking for the same condition as above but a longer sleep time

Both approaches kind of work, but the delay between the time that the request was supposed to be sent and the time that it has actually been sent is way too high. Is there any way to send the requests with higher precision?

Edit: The suggests approaches work really well. However, the delay is still extremely high for many requests. Apparantly, the reason for this is my SendRequest() method:

private static async Task SendRequest()
{
    // Log time difference
    string url = "http://www.request.url/newaction";
    WebRequest webRequest = WebRequest.Create(url);
    try
    {
        WebResponse webResponse = await webRequest.GetResponseAsync();
    }
    catch (Exception e) { }
 }

Note that my web service does not return any response, maybe this is the reason for the slow down? Can I send the request without waiting for the response?

Upvotes: 1

Views: 66

Answers (2)

Romano Zumb&#233;
Romano Zumb&#233;

Reputation: 8079

I would suggest to use a timer object to trigger the requests:

// In Form_Load or another init method
Timer tRequest = new Timer();
tRequest.Interval = 500;
tRequest.Tick += TRequest_Tick;

private void TRequest_Tick(object sender, EventArgs e)
{
     var sendTimes = times.Where(t => t.AddMilliseconds(-500) < DateTime.Now && t.AddMilliseconds(500) > DateTime.Now);

     foreach(DateTime sendTime in sendTimes)
     {
         SendRequest();
     }
}

Upvotes: 2

Aron
Aron

Reputation: 15772

Why are you doing this with multiple thread? Threading requires slow sleep/wake context switching. You could just do this all with timers/async calls.

List<DateTime> scheduledTimes = ...;
List<Task> requests = scheduledTimes
                         .Select(t => t - DateTime.Now)
                         .Select(async delay => 
                         {
                             await Task.Delay(delay);
                             SendRequest();
                         })
                         .ToList();

await Task.WhenAll(requests);

The above code will in one thread schedule all the requests onto the SynchronizationContext and run them.

Simples.

Upvotes: 2

Related Questions