2 回答

TA貢獻(xiàn)1806條經(jīng)驗(yàn) 獲得超8個(gè)贊
更新
正如我剛剛注意到您在評(píng)論中提到的那樣,問(wèn)題是由數(shù)學(xué)計(jì)算引起的。
將計(jì)算和更新數(shù)據(jù)庫(kù)的部分分開(kāi)會(huì)更好。
對(duì)于計(jì)算部分,使用Parallel.ForEach()以便優(yōu)化您的工作,您可以控制線程數(shù)。
只有在所有這些任務(wù)完成之后。用于async-await將您的數(shù)據(jù)更新到數(shù)據(jù)庫(kù),無(wú)需SemaphoreSlim我提及。
public static async Task<int> Work()
{
var id = await CreateIdInDB() // async create record in DB
// run background task, don't wait when it finishes
Task.Run(async () => {
//Calculation Part
ConcurrentBag<int> data = new ConcurrentBag<int>();
Parallel.ForEach(
listOfData,
new ParallelOptions { CancellationToken = token, MaxDegreeOfParallelism = 3 },
x => {ConcurrentBag.Add(calculationPart(x))});
//Update DB part
int[] data_arr = data.ToArray();
List<Task> worker = new List<Task>();
foreach (var i in data_arr)
{
worker.Add(DBPart(x));
}
await Task.WhenAll(worker);
});
// return created id immediately
return id;
}
當(dāng)你async-await在Parallel.forEach.
首先,閱讀第一個(gè)和第二個(gè)答案的這個(gè)問(wèn)題。將這兩者結(jié)合起來(lái)毫無(wú)意義。
實(shí)際上async-await會(huì)最大限度地利用可用線程,所以簡(jiǎn)單地使用它。
public static async Task<int> Work()
{
var id = await CreateIdInDB() // async create record in DB
// run background task, don't wait when it finishes
Task.Run(async () => {
List<Task> worker = new List<Task>();
foreach (var i in listOfData)
{
worker.Add(ProcessSingle(x));
}
await Task.WhenAll(worker);
});
// return created id immediately
return id;
}
但是還有另一個(gè)問(wèn)題,在這種情況下,這些任務(wù)仍然一起開(kāi)始,消耗你的 CPU 使用率。
因此,為避免這種情況,請(qǐng)使用 SemaphoreSlim
public static async Task<int> Work()
{
var id = await CreateIdInDB() // async create record in DB
// run background task, don't wait when it finishes
Task.Run(async () => {
List<Task> worker = new List<Task>();
//To limit the number of Task started.
var throttler = new SemaphoreSlim(initialCount: 20);
foreach (var i in listOfData)
{
await throttler.WaitAsync();
worker.Add(Task.Run(async () =>
{
await ProcessSingle(x);
throttler.Release();
}
));
}
await Task.WhenAll(worker);
});
// return created id immediately
return id;
}
此外,不要Task.Factory.StartNew()在簡(jiǎn)單Task.Run()就足以完成您想要的工作時(shí)使用,請(qǐng)閱讀 Stephen Cleary 撰寫(xiě)的這篇出色的文章。

TA貢獻(xiàn)1830條經(jīng)驗(yàn) 獲得超3個(gè)贊
如果您更熟悉“傳統(tǒng)”并行處理概念,請(qǐng)像這樣重寫(xiě)您的 ProcessSingle() 方法:
public static void ProcessSingle(MyInputData inputData)
{
var dbData = GetDataFromDb(); // get data from DB async using Dapper
// some lasting processing (sync)
SaveDataToDb(); // async save processed data to DB using Dapper
}
當(dāng)然,您最好也以類似的方式更改 Work() 方法。
- 2 回答
- 0 關(guān)注
- 1156 瀏覽
添加回答
舉報(bào)