我有一个要求,我从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秒,我将再次调用相同的功能,以便为接收响应提供时间。
如果我的问题听起来很愚蠢,请纠正我。
答案 0 :(得分:1)
你永远不应该使用Thread.Sleep
,因为在其他人中你不知道3000ms是否足够而不是使用Thread类你应该使用Task类,这是更好的选择,因为它提供了一些额外的功能,线程池管理等我无法访问IDE,但您应该尝试使用Task.Factory.StartNew异步调用您的请求,然后您的函数GetJobwiseDetail应该返回一些您要保存到数据库的值,然后使用.ContinueWith与委托,应该将您的功能结果保存到数据库中。如果您能够使用.NET 4.5,则应尝试使用async / await功能。
更简单的解决方案:
Parallel.ForEach
在互联网上获取有关它的一些细节,你必须对线程一无所知。它将在另一个线程上调用每个循环迭代。
答案 1 :(得分:1)
首先,避免不惜一切代价在代码中启动新的Thread
;这些线程会像崩溃的星星那样吸引你的记忆,因为每个线程都会分配大约1MB的内存。
现在代码 - 根据框架,您可以从以下选项中选择:
ThreadPool.QueueUserWorkItem
适用于旧版本的.NET Framework Parallel.ForEach
for .NET Framework 4 async
和await
for .NET Framework 4.5 TPL Dataflow
也适用于.NET Framework 4.5 您展示的代码非常适合Dataflow,我也不建议在这里使用async/await
因为它的用法会改变您的示例是一种fire and forget
机制,这违反了使用的建议async/await
。
要使用Dataflow
,您需要排成一行:
TransformBlock
,它将字符串作为输入,并将从API返回响应BroadcastBlock
将广播响应ActionBlock
s;一个用于存储数据库中的数据,另一个用于调用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();
答案 2 :(得分:-1)
尝试使用async,如下所示。
async Task Task_MethodAsync()
{
// . . .
// The method has no return statement.
}