[英]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.