[英]To call method asynchronously from loop in c#
我有一个从Sailthru API中提取数据的要求,问题是如果我同步进行调用将花费很多时间,因为响应时间取决于数据。我对线程技术有很多新知识并尝试了一些东西,但没有似乎按预期工作。 任何人都可以指导。 下面是我的示例代码
public void GetJobId()
{
Hashtable BlastIDs = getBlastIDs();
foreach (DictionaryEntry entry in BlastIDs)
{
Hashtable blastStats = new Hashtable();
blastStats.Add("stat", "blast");
blastStats.Add("blast_id", entry.Value.ToString());
//Function call 1
//Thread newThread = new Thread(() =>
//{
GetBlastDetails(entry.Value.ToString());
//});
//newThread.Start();
}
}
public void GetBlastDetails(string blast_id)
{
Hashtable tbData = new Hashtable();
tbData.Add("job", "blast_query");
tbData.Add("blast_id", blast_id);
response = client.ApiPost("job", tbData);
object data = response.RawResponse;
JObject jtry = new JObject();
jtry = JObject.Parse(response.RawResponse.ToString());
if (jtry.SelectToken("job_id") != null)
{
//Function call 2
Thread newThread = new Thread(() =>
{
GetJobwiseDetail(jtry.SelectToken("job_id").ToString(), client,blast_id);
});
newThread.Start();
}
}
public void GetJobwiseDetail(string job_id, SailthruClient client,string blast_id)
{
Hashtable tbData = new Hashtable();
tbData.Add("job_id", job_id);
SailthruResponse response;
response = client.ApiGet("job", tbData);
JObject jtry = new JObject();
jtry = JObject.Parse(response.RawResponse.ToString());
string status = jtry.SelectToken("status").ToString();
if (status != "completed")
{
//Function call 3
Thread.Sleep(3000);
Thread newThread = new Thread(() =>
{
GetJobwiseDetail(job_id, client,blast_id);
});
newThread.Start();
string str = "test sleeping thread";
}
else {
string export_url = jtry.SelectToken("export_url").ToString();
TraceService(export_url);
SaveCSVDataToDB(export_url,blast_id);
}
}
我希望函数调用1异步启动(或可能在3秒钟的间隔后才能避免在处理器上加载)。 在功能调用3中 ,如果状态未完成(延迟3秒)以给出接收响应的时间,我将再次调用同一功能。
如果我的问题听起来很愚蠢,也请纠正我。
您永远不应该那样使用Thread.Sleep
,因为除其他外,您不知道3000ms是否足够,您应该使用Task类,而不是使用Thread类,因为它提供了一些附加功能,线程池管理等,因此它是更好的选择。我没有访问IDE的权限,但是您应该尝试使用Task.Factory.StartNew异步调用您的请求,然后您的函数GetJobwiseDetail应该返回一些要保存到数据库的值,然后将.ContinueWith与委托一起使用,这样可以保存您的函数结果存入数据库。 如果您能够使用.NET 4.5,则应尝试使用异步/等待功能。
更简单的解决方案:
Parallel.ForEach
在Internet上获取有关它的一些详细信息,而您不必了解线程。 它将在另一个线程上调用每个循环迭代。
首先,不惜一切代价避免在代码中启动新的Thread
; 这些线程将像崩溃的星星一样消耗您的内存,因为每个线程都分配有〜1MB的内存。
现在查看代码-根据框架,您可以从以下选项中进行选择:
ThreadPool.QueueUserWorkItem
Framework的较旧版本的ThreadPool.QueueUserWorkItem
Parallel.ForEach
async
并await
.NET Framework 4.5 TPL Dataflow
也适用于.NET Framework 4.5 您显示的代码非常适合Dataflow,并且我也不建议async/await
这里使用async/await
,因为它的用法将转换您的示例,是一种即发即fire and forget
机制,与使用async/await
的建议async/await
。
要使用Dataflow
您需要大致Dataflow
几行:
TransformBlock
,它将字符串作为输入,并将返回API的响应 BroadcastBlock
,它将广播响应到 ActionBlock
; 一个用于将数据存储在数据库中,另一个用于调用TraceService
该代码应如下所示:
var downloader = new TransformBlock<string, SailthruResponse>(jobId =>
{
var data = new HashTable();
data.Add("job_id", jobId);
return client.ApiGet("job", data);
});
var broadcaster = new BroadcastBlock<SailthruResponse>(response => response);
var databaseWriter = new ActionBlock<SailthruResponse>(response =>
{
// save to database...
})
var tracer = new ActionBlock<SailthruResponse>(response =>
{
//TraceService() call
});
var options = new DataflowLinkOptions{ PropagateCompletion = true };
// link blocks
downloader.LinkTo(broadcaster, options);
broadcaster.LinkTo(databaseWriter, options);
broadcaster.LinkTo(tracer, options);
// process values
foreach(var value in getBlastIds())
{
downloader.Post(value);
}
downloader.Complete();
尝试使用异步,如下所示。
async Task Task_MethodAsync()
{
// . . .
// The method has no return statement.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.