我有一個長時間運行的任務,我不想阻止用戶界面,所以我得到了一個DispatcherTimer
,我使用它的tick事件來檢查任務屬性IsCompleted
但這會導致某種形式的死鎖,因爲我的應用程序停止響應是否可以輪詢任務完成?
public partial class MainWindow : Window
{
DateTime beginFirstPhase;
DateTime beginSecondPhase;
DispatcherTimer dispatcherTimer = new DispatcherTimer();
IEnumerable<string> collection;
Task firstPhaseTask;
Task secondPhaseTask;
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
progressTxtBox.AppendText("Entering button click event handler\n");
beginFirstPhase = DateTime.Now;
dispatcherTimer.Tick += DispatcherTimer_Tick_FirstPhase;
dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
dispatcherTimer.Start();
progressTxtBox.AppendText("Begining First Phase now\n");
firstPhaseTask = Task.Factory.StartNew(() =>
/*this is basically a big linq query over a huge collection of strings
(58 thousand+ strings). the result of such query is stored in the field named
collection, above*/), TaskCreationOptions.PreferFairness);
progressTxtBox.AppendText("Awaiting First Phase completion...\n");
}
private void DispatcherTimer_Tick_FirstPhase(object sender, EventArgs e)
{
TimeSpan span = DateTime.Now - beginFirstPhase;
//not even the line bellow is executed.
statusTextBlock.Text = $"Running: {span.ToString()}";
if (firstPhaseTask.IsCompleted)
{
dispatcherTimer.Stop();
progressTxtBox.AppendText($"First Phase completed in {span.ToString()}\n");
secondPhase();
}
}
private void secondPhase()
{
beginSecondPhase = DateTime.Now;
progressTxtBox.AppendText("Begining Second Phase now\n"));
dispatcherTimer.Tick -= DispatcherTimer_Tick_FirstPhase;
dispatcherTimer.Tick += DispatcherTimer_Tick_SecondPhase;
dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
dispatcherTimer.Start();
int counter = 0;
secondPhaseTask = Task.Factory.StartNew(() =>
{
foreach (string str in collection)
{
Dispatcher.Invoke(() => progressTxtBox.AppendText($"iteration <{counter++}>\n"));
IEnumerable<Tuple<string, string> queryResult; // = another linq query
foreach (var tuple in queryResult)
{
Dispatcher.Invoke(() => outputListView.Items.Add($"{tuple.Item1} {tuple.Item2} {str}"));
}
}
}, TaskCreationOptions.PreferFairness);
}
private void DispatcherTimer_Tick_SecondPhase(object sender, EventArgs e)
{
TimeSpan span = DateTime.Now - beginSecondPhase;
statusTextBlock.Text = $"Running: {span.ToString()}";
if (secondPhaseTask.IsCompleted)
{
dispatcherTimer.Stop();
progressTxtBox.AppendText($"Second Phase completed in {span.ToString()}\n");
progressTxtBox.AppendText("Execution Complete");
}
}
}
這是什麼原因阻塞? Task.IsCompleted
是否阻止了調用者的線程? 難道根本就無法輪詢這樣的任務嗎?如果不是,還有其他選擇嗎?
編輯:親愛的估計StackOverflow社區的成員,我收到幾個答案,基本上說「不要這樣做,這樣更好」。這些都是非常好的答案,我爲他們感謝你們。但我的問題是這樣的:「是否可以輪詢任務完成,以及如何完成」。沒關係,這是一個糟糕的設計模式,因爲這不是問題的一部分。我知道我可以重寫代碼來使用await和異步,但是,由於我是自學的,因此我認爲探索語言可以做什麼是一個好主意。
這就像是我問了一個關於goto
如何工作的問題,我得到的所有答案都是爲什麼不使用goto
以及如何替換它。我明白你們都希望儘可能地提供幫助,爲我提供我所選擇的設計是不好的知識,但是如果不幫助我實施我的不良選擇,那麼你就拒絕了我有關如何去做的知識。我虛心相信這違背了這個社區的精神。我希望這個附錄不會冒犯任何人,我只有尊重社區所有成員,我希望我已經說得很清楚。
這不會編譯:'firstPhaseTask = await TaskFactor.StartNew(...)'。另外,我第二階段只能在第一階段完成後纔開始,否則對象將處於不一致狀態。這就是爲什麼我需要調查第一階段是否完成。 – FinnTheHuman
不,如果您使用閉包,則無需進行輪詢,但它不會編譯,因爲您需要將代碼更改爲與我的建議類似。如果您需要查詢結果,請按照建議中所示返回結果。當編譯器命中await狀態時,該線程會自動掛起,直到設置var結果的恢復。然後你是在主線程上,當第二次等待被擊中時,如果你有一個「閉包」,同樣的事情發生...... –