以下程序是我整個程式的一段縮碼,
大體意思就是一個文本框,想多執行緒開幾個任務,同時每個任務完成后顯示在文本框中,
但現在的結果是文本框根本不顯示,只顯示最后一個結果49,而我要求從1到49滾動(當然我也知道不一定是按順序來),
private async void button1_Click(object sender, EventArgs e)
{
await Do(); //
Console.WriteLine("全部完成了");
}
public async Task Do()
{
Console.WriteLine($"當前主執行緒的ID是{Thread.CurrentThread.ManagedThreadId}");
List<Task> TaskList = new List<Task>();
var scheduler = new LimitedConcurrencyLevelTaskScheduler(70);
for (int i = 0; i < 50; i++)
{
Console.WriteLine($"當前{i}的ID是{Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(100);
TaskList.Add(Task.Factory.StartNew(t =>
{
//這里插一個大量耗時程序
textBox1Set(Convert.ToInt32(t));
}, i, CancellationToken.None, TaskCreationOptions.None, scheduler));
}
await Task.WhenAll(TaskList.ToArray());
Console.WriteLine($"結束了");
}
public void textBox1Set(int I)//供當前及后續類寫日志用
{
Console.WriteLine($"當前{I}的textBox1SetID是{Thread.CurrentThread.ManagedThreadId}");
textBox1.Invoke((EventHandler)delegate
{
textBox1.Text = I.ToString();
Console.WriteLine($"當前{I}的textBox1SetID的BeginInvoke是{Thread.CurrentThread.ManagedThreadId}");
});
}
網上搜了半天,大體搞明白了原因是多執行緒把UI阻塞了(具體什么原因也不懂)
我想把“ await Do(); // ”改為 await Task.Run(() => { Do(); });
卻有提示“此呼叫不會等待”; 也不敢用,請高手指點。

uj5u.com熱心網友回復:
private class UISync{
private static ISynchronizeInvoke Sync;
public static void Init(ISynchronizeInvoke sync)
{
Sync = sync;
}
public static void Execute(Action action)
{
Sync.BeginInvoke(action, null);
}
}
void XXXXX(object sender, EventArgs e)
{
UISync.Execute(() => XXXXXXXXXXXXXXXXXXX);
}
uj5u.com熱心網友回復:
Thread.Sleep(100);請先把這個去掉 ,因為你說的是“模擬一個大量耗時的動作”,但其實你后面的代碼根本就不會耗時
而你每次回圈來個sleep其實是讓主執行緒睡覺,但是后面子task早就完成了,那么最后的結果其實就是子task早就是完成到49了,而你的主執行緒才重繪。
你前一個帖子我們已經說過了,如果不到另外啟動一個task的情況,他其實只是一個io等待,他不會搞啥啟動新執行緒,所以這個sleep其實是讓主執行緒休眠
你想達到你的目的,請這樣寫
TaskList.Add(Task.run(asycn t =>
{
//這里插一個大量耗時程序
await Task.Delay(2000);//到了這個Task,他才會進入執行緒池,同時這個耗時動作,當然在這個task里模擬,這里用task.run是防止你那個waitall不帶入問題,我們已知task.factory.startnew 默認不帶背景關系,尤其是里面還有await的異步情況
textBox1Set(Convert.ToInt32(t));
}, i, Cancel
uj5u.com熱心網友回復:
非常感謝,我琢磨透了,作為這個問題本身,你給我指出了根本的原因,那就是我本身的代碼有問題,那個耗時程序(Thread.Sleep(100);)我放錯位置了,導致多執行緒已經運行完了,Ui才結束,所以肯定顯示最終結果49,作為解決方案,我其實只要把這個程序換個位置不就行了,如下,已測驗通過,滿足我要求
public async Task Do()
{
Console.WriteLine($"當前主執行緒的ID是{Thread.CurrentThread.ManagedThreadId}");
List<Task> TaskList = new List<Task>();
var scheduler = new LimitedConcurrencyLevelTaskScheduler(70);
for (int i = 0; i < 50; i++)
{
Console.WriteLine($"當前{i}的ID是{Thread.CurrentThread.ManagedThreadId}");
TaskList.Add(Task.Factory.StartNew(t =>
{
Thread.Sleep(100);
textBox1Set(Convert.ToInt32(t));
}, i, CancellationToken.None, TaskCreationOptions.None, scheduler));
}
await Task.WhenAll(TaskList.ToArray());
Console.WriteLine($"結束了");
}
作為延申,我實在沒明白,為什么要把“task.factory.startnew ”改為“task.run”,雖然你解釋了(防止你那個waitall不帶入問題),但還是沒懂。
還有,為什么把“ Thread.Sleep(1000);”改為“asycn await Task.Delay(2000) ”
我上面用法不是也挺好嗎?
再次感謝!
uj5u.com熱心網友回復:
最后的問題是這樣。前面說了,異步的實質是IO等待。IO等待屬于IO操作理論上不消耗cpu,而執行緒的本質是“cpu并發”屬于需要耗CPU,所以我們只是選擇不耗CPU的就不耗cpu。
同時因為await操作,所以使用run,因為run是對startnew的簡化封裝,他內部其實改寫成了 await task<task>這種方式,同時還改寫了啟動引數,所以不會對你后面的waitall產生影響
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/272720.html
標籤:C#
上一篇:C# winForm socket服務器和客戶端通信
下一篇:問個小問題
