2015-12-08 123 views
0

我在玩任務我想推遲我的任務執行。推遲執行任務

我有一個樣品的方法是這樣的:

private async Task<bool> DoSomething(string name, int delayInSeconds) 
{ 
    Debug.WriteLine($"Inside task named: {name}"); 
    await Task.Delay(TimeSpan.FromSeconds(delayInSeconds)); 
    Debug.WriteLine($"Finishing task named: {name}"); 
    return true; 
} 

我想先創建一些任務,然後執行一些工作,在這之後運行這些任務。由於線路Task<bool> myTask = DoSomething("Name", 4);大火馬上任務,我已經想通是這樣的:

string[] taskNames = new string[2]; 

Task<Task<bool>>[] myTasks = new Task<Task<bool>>[2]; 
myTasks[0] = new Task<Task<bool>>(async() => await DoSomething(taskNames[0], taskNames[0].Length)); 
myTasks[1] = new Task<Task<bool>>(async() => await DoSomething(taskNames[1], taskNames[1].Length)); 

// I think I can declare it also like this, but this will create tasks later 
//IEnumerable<Task<Task<bool>>> myTasks = taskNames.Select(x => new Task<Task<bool>>(async() => await DoSomething(x, x.Length))); 

taskNames[0] = "First"; 
taskNames[1] = "Second"; 

Debug.WriteLine($"Tasks created"); 

var results = await Task.WhenAll(myTasks.Select(x => { x.Start(); return x.Unwrap(); })); 
Debug.WriteLine($"Finishing: {results.Select(x => x.ToString()).Aggregate((a,b) => a + "," + b) }"); 

可以這樣做不同的方式,沒有包裝任務?

回答

2

你可以使用Task - 生產委託給簡化事情有點:

string[] taskNames = new string[2]; 

Func<Task<bool>>[] myTasks = new Func<Task<bool>>[2]; 
myTasks[0] = new Func<Task<bool>>(async() => await DoSomething(taskNames[0], taskNames[0].Length)); 
myTasks[1] = new Func<Task<bool>>(() => DoSomething(taskNames[1], taskNames[1].Length)); // Shorter version, near-identical functionally. 

// I think I can declare it also like this, but this will create tasks later 
//IEnumerable<Task<Task<bool>>> myTasks = taskNames.Select(x => new Task<Task<bool>>(async() => await DoSomething(x, x.Length))); 

taskNames[0] = "First"; 
taskNames[1] = "Second"; 

Debug.WriteLine($"Tasks created"); 

var results = await Task.WhenAll(myTasks.Select(x => x())); 
Debug.WriteLine($"Finishing: {results.Select(x => x.ToString()).Aggregate((a, b) => a + "," + b) }"); 

買者DoSomething將執行同步到第一個await當你調用這些代表,這樣的行爲是相似的,但不是正好是相同。

或者,您的基於IEnumerable的解決方案也可以正常工作。只需在開始時寫一個迭代器方法和yield return任務。

個人雖然我只是這樣做:

string[] taskNames = new string[2]; 

taskNames[0] = "First"; 
taskNames[1] = "Second"; 

var results = await Task.WhenAll(taskNames.Select(n => DoSomething(n, n.Length))); 
Debug.WriteLine($"Finishing: {results.Select(x => x.ToString()).Aggregate((a, b) => a + "," + b) }"); 
+0

不錯 - 我沒想過用* Func *來創建任務,什麼都不需要進一步解開。事實證明,與所有這些樣本一起玩,你的解決方案有很大的不同 - 所有的任務運行在同一個UI線程上,它們運行良好,因爲它們是異步的。 – Romasz

+0

沒錯,那就是我的「警告」部分所提到的。如果你想盡快把事情推送到線程池,你可以讓你的Func返回'Task.Run(()=> DoSomething(...))',而不必拆開結果 - 選擇仍然存在儘管我必須承認,它會導致一些相當粗俗的語法)。 –

1

你不只是「創造一個Task」在你的例子。你正在調用一個方法DoSomething,即返回 a Task。假設這些方法是async方法,則在編譯器生成的代碼後面創建和啓動。

此問題的解決方案很簡單:在您準備好運行方法之前,請不要調用該方法。想象一下,你所要求的行爲在任何其他環境中有多混淆。

+0

一般我贊同。儘管我想將任務實例從執行中分離出來。儘管這只是爲了學習一些東西。 – Romasz