मुझे पता है कि await में foreach का उपयोग करना प्रदर्शन के कारण अच्छा अभ्यास नहीं है, क्योंकि यह प्रत्येक कार्य के लिए क्रमिक रूप से प्रतीक्षा करेगा।

foreach (var task in result)
{
     task.Stages = await GetStagesForTask(task.Id);
}

तो मैं उस कोड को कैसे सुधार सकता हूं? मैं ऐसा कुछ करने की कोशिश कर रहा था:

List<Task> listOfTasks = new List<Task>();

foreach (var task in result)
{
    var stage = GetStagesForTask(task.Id);
    listOfTasks.Add(stage);
    task.Stages = stage;
}

await Task.WhenAll(listOfTasks);

लेकिन निश्चित रूप से यहां गलत प्रकार के कारण task.Stages = stage; यह काम नहीं करेगा।

0
DiPix 28 जून 2021, 16:59

4 जवाब

सबसे बढ़िया उत्तर

आप एक एसिंक्रोनस प्रतिनिधि के साथ LINQ का उपयोग कर सकते हैं:

var tasks = result.Select(async task =>
{
    var stage = await GetStagesForTask(task.Id);
    task.Stages = stage;
});

await Task.WhenAll(tasks);

या एक स्थानीय समारोह पेश करें:

List<Task> listOfTasks = new List<Task>();

async Task SetStagesAsync(YourTask task)
{
    task.Stages = await GetStagesForTask(task.Id);
}

foreach (var task in result)
{
    listOfTasks.Add(SetStagesAsync(task));
}

await Task.WhenAll(listOfTasks);

या यहाँ तक कि दोनों का एक संयोजन:

async Task SetStagesAsync(YourTask task)
{
    task.Stages = await GetStagesForTask(task.Id);
}

await Task.WhenAll(result.Select(SetStagesAsync));
3
Johnathan Barclay 30 जून 2021, 14:39

जॉनाथन बार्कले का समाधान एकदम सही है यदि आप अपनी संस्थाओं की चरणों संपत्ति को समवर्ती रूप से बदलने में कोई आपत्ति नहीं करते हैं . लेकिन अगर आप सभी एसिंक्रोनस ऑपरेशन पूरा होने तक म्यूटेशन को स्थगित करना पसंद करते हैं, तो आप अपनी संस्थाओं को Tasks की सूची में प्रोजेक्ट करने पर विचार कर सकते हैं, फिर प्रतीक्षा करें Task.WhenAll का उपयोग करके इन कार्यों को करना, और अंत में सभी परिणामी कार्रवाईs:

Task<Action>[] tasks = entities.Select(async entity =>
{
    var stages = await GetStagesForEntityAsync(entity.Id);
    return new Action(() => entity.Stages = stages);
}).ToArray();

Action[] actions = await Task.WhenAll(tasks);

foreach (var action in actions) action.Invoke();

उपरोक्त उदाहरण में मैंने आपके उदाहरण के task और result चर का नाम बदलकर entity/entities कर दिया है, ताकि आपकी संस्थाओं और अंतर्निहित Task क्लास।

LINQ Select ऑपरेटर एक एन्यूमेबल को दूसरे में प्रोजेक्ट करना आसान बनाता है, और यह विशेष रूप से तब आसान होता है जब आप ऑब्जेक्ट्स की सूची से कस्टम कार्यों की सूची बनाना चाहते हैं।

1
Theodor Zoulias 29 जून 2021, 08:05

इस समस्या को हल करने का एक साफ-सुथरा तरीका है कि प्रत्येक कार्य के लिए एक धागा बनाया जाए, await अलग-अलग थ्रेड्स के अंदर होगा। तो, आप एक foreach में धागे बनाएंगे, वे अलग-अलग धागे में प्रतीक्षा करेंगे और फिर दूसरा foreach प्रत्येक धागे के लिए .Join() को कॉल करेगा। इस तरह आपके पास अनुक्रमिक प्रतीक्षा नहीं होगी, लेकिन धागे बनाएं, वे समानांतर में काम करेंगे और आप अपने सबसे लंबे कार्य के रूप में उतना ही इंतजार करेंगे जितना सभी कार्यों के लिए आवश्यक समय के योग के रूप में नहीं होगा।

हालांकि, यदि आपके पास कई कार्य हैं, तो सभी संसाधनों को खाने से सावधान रहें। यदि आपके पास कई कार्य हैं, तो उन्हें शायद १० धागों के टुकड़ों में तोड़ दें और ऊपर वर्णित दृष्टिकोण को लागू करें।

-1
Lajos Arpad 28 जून 2021, 14:42

समानांतर के लिए यह मामला है: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.for?view=net-5.0

यह मानते हुए कि आप परिणाम को सूची में परिवर्तित कर सकते हैं ताकि आप इसके आइटम्स को index.

किसी तरह यह @LajosArpad के प्रस्ताव के समान है, बस इसे करने का यह बहुत आसान तरीका है क्योंकि उन्होंने जिन संभावित समस्याओं का उल्लेख किया है उन्हें रनटाइम द्वारा स्वचालित रूप से नियंत्रित किया जाता है।

-1
Ivan Ičin 28 जून 2021, 14:48