我有以下情况。我正在使用.net 4.5.1
我有一个名为ServiceRequest()
;
请求使用tcpclient与服务器建立连接并从中获取数据。
运行ServiceRequest.Start()
时启动计时器,然后每隔x分钟向服务器发出一次请求。 (我目前在服务类中没有线程)
所以我现在使用它的方式:
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);
}
}
现在我想让每个请求以异步方式运行。
这样做最好的方法是什么?
我是否只为每个请求创建一个线程?或者我应该使用线程池?我是线程的新手,所以请简单地尝试解释,也只是注意不会超过50个ServiceRequests同时运行。我不确定这是否可以在实现它的方式中发挥作用。
我关注的是回调函数,现在一旦我对每个RequestService
进行了线程化,我是否需要对回调函数做任何事情,因为它会在任何给定时间从几个不同的线程调用? / p>
答案 0 :(得分:1)
您有4个选项
System.Threading's Thread
ThreadPoll.QueueUserWorkItem
这样更好,因为它利用了 ThreadPool 。但是它没有其他方法灵活,因为它不允许你从回调中返回任何内容StartNew<T>
返回Task<T>
您可以保留的结果,当您需要结果时,您可以调用'task.Result'来阻止调用线程直到任务完成。async/await
要使用async / await,您的方法必须返回Task<T>
,在您的情况下Task<ResponseObject>
。按照惯例,方法名称以Async结尾,并具有关键字async
在您的示例中,您可以更改ServiceRequest的Start方法,使其为异步:
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
}
然后您可以更改StartServiceRequests并确保定期调用它(而不是在启动时执行[这只是一个建议]):
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
}
}
这将利用 ThreadPool ,它将管理当前正在执行的线程数,并将管理现有线程的创建和处理。有时,了解如何将新线程添加到 ThreadPool 非常重要。使用Task.Factory.StartNew(或使用async / await)时,不一定会立即创建新线程。
有一个.5秒的等待,检查 ThreadPool 是否没有改变(意味着所有线程都在工作),然后添加新线程(再次,添加一个线程有很大的成本)。
但在你的情况下,你想要执行50个并行请求(你知道每个请求需要时间,即超过.5秒),所以你想要所有人开始。您可以更改 ThreadPool (SetMinThreads)中的最小线程数并将其设置为50(这并不意味着将立即在 ThreadPool中创建50个线程< / em>,它只意味着.5秒没有等待,直到ThreadPool达到50个线程)。
以下是一个例子:
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.
}
答案 1 :(得分:0)
首先,您绝对不希望为此手动创建线程。所以是的,你应该使用线程池。根据您所定位的.net框架的版本,您可以使用TPL(任务并行库)创建任务以进行服务调用。这些任务使用线程池中的线程执行代码(默认情况下)。可以找到更多信息here。
如果使用TPL而不是回调,则可以使用continuation,并在代码执行后运行其他任务。