Question

I have the following situation. I am using .net 4.5.1

I have a class called ServiceRequest();

Request makes a connection using tcpclient to a server and gets data from it.

When you run ServiceRequest.Start() It starts a timer that then makes the request to the server every x minutes. ( I currently have no threading in the service class)

So the way I use it now:

private List<ServiceRequest> ServiceCommuncators = new List<ServiceRequest>();

//Load Services To monitor
serviceResp = new EFServiceRepository();
IList<Service> Services = GetAllServices();

//Setup Services
ItterateServices(Services);

//Start Service Requests
StartServiceRequests();

//Functions:
private void ItterateServices(IList<Service> services)
    {
        for (int i = 0; i < services.Count; i++)
        {
            ServiceCommuncators.Add(new ServiceRequest(i, services[i].IpAddress, services[i].Port, services[i].PollInterval, ServicRequestCallBackFunction));
        }
    }

private void StartServiceRequests()
{
  foreach (ServiceRequest s in ServiceCommuncators)
  {
     s.Start();
  }
}

  public void ServicRequestCallBackFunction(ResponseObject response)
    {
        if (response.Successfull)
        {
            RecievedsuccessfulResponse(response);
        }
        else
        {
            // ServiceRequest Failed
            RecievedFailedResponse(response);
        }
    }

Now I want to make each request run asynchronously.

  1. What would be the best way to go about doing this?
    Do I just create a thread for each request? Or should I use threadpool? I am new to threading so please try explain simply, also just a note there wont be more than 50 ServiceRequests running at once. I'm not sure if that could play a role in which way to implement it.

  2. My concern is the call back function, Now once I have threaded each RequestService do I need to do anything to the callback function as it will be called from several different threads at any given time?

Was it helpful?

Solution

You have 4 options

  1. Use System.Threading's Thread
    This is probably the worst option, since it doesn't take advantage of the ThreadPool. And since you are spinning up a considerable amount of threads (each one has approx. 1Mb of overhead, because each one has its stack among other things)
  2. Use ThreadPoll.QueueUserWorkItem This is better, since it takes advantage of the ThreadPool. However it is less flexible than other methods since it won't allow you to return anything from the callback
  3. Use Task.Factory.StartNew
    If for some reason you can't use async/await this is the way to go. It takes advantage of the ThreadPool and is very flexible in terms of how it is used. StartNew<T> returns Task<T> which you can hold to and when you need the result you can call 'task.Result' which will block the calling thread until the task finishes.
  4. Use async/await
    This is the easiest and the most in vogue way of doing async these days, and rightly so. It is just syntactic sugar for (3).

To use async/await your method has to return Task<T>, in your case Task<ResponseObject>. By convention the method name end with Async and has the keyword async

In your example, you can change ServiceRequest's Start method so that it is async:

public async Task<ResponseObject> StartAsync()
{
  //make the request using await
  //for example return await caller.PerformRequestAsync
  //an important note here, if the method you need to call is not async, you can use await Task.Factory.StartNew<ResponseObject>(method that returns ResponseObject)

  return response; //response is an instance of ResponseObject
}

And then you can change StartServiceRequests and make sure it is called periodically (instead of doing it on start [this is just a suggestion]):

private async void StartServiceRequestsAsync()
{
  IEnumerable<Task<ResponseObject>> requests = new List<Task<ResponseObject>>();
  foreach (ServiceRequest s in ServiceCommuncators)
  {
     requests.Add(s.StartAsync()); //this is non-blocking
  }

  foreach(var executingRequest in requests)
  {
     ResponseObject response = await executingRequest;
     //do something with response
  }
}

This will take advantage of the ThreadPool, which will manage the number of threads currently executing and will manage the creation and disposing of existing threads. Sometimes it is important to know how new threads get added to the ThreadPool. A new thread won't necessarily be created immediately when you use Task.Factory.StartNew (or you use async/await).

There's a .5sec wait that checks if the ThreadPool doesn't change (meaning that all threads are doing work) then new threads are added (again, adding a thread has a significant cost).

But in your case you want to perform 50 parallel requests (which you know each will take time, i.e. more than .5sec) so you want all to start. You can change the minimum number of threads in the ThreadPool(SetMinThreads) and set it to 50 (this doesn't mean that 50 threads will immediately be created in the ThreadPool, it just means there's .5sec no wait until the ThreadPool reaches 50 threads).

Here's an example:

int minWorker, minIOC;
// Get the current settings.
ThreadPool.GetMinThreads(out minWorker, out minIOC);
// Change the minimum number of worker threads to 50, but 
// keep the old setting for minimum asynchronous I/O  
// completion threads. 
if (ThreadPool.SetMinThreads(50, minIOC))
{
    // The minimum number of threads was set successfully.
}
else
{
    // The minimum number of threads was not changed.
}

OTHER TIPS

First, you definitely don't want to to be manually creating threads for this. So yes, you should be making use of the thread pool. Depending upon what version of the .net framework you are targeting, you can make use of TPL (Task Parallel Library) to create Tasks to make your service calls. These tasks execute code using threads from the threadpool (by default). More info can be found here.

If you use the TPL, rather than callbacks, you can use continuations, with are other tasks to be run after the code has executed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top