玩轉C#之【執行序-執行緒安全】

更新於 發佈於 閱讀時間約 33 分鐘

介紹

委派的非同步方法

可以透過BeginInvoke執行委派的非同步方法
Action<T>.BeginInvoke(<T> obj,AsyncCallback callback,Object @object)
第一個內容的 obj,只的是要傳入acction委派的參數
第二個AsyncCallback,是當Action內容執行完後下一段要執行的程式碼
第三個參數 可以讓第二個參數AsyncCallback透過ia.AsyncState讀取到
Action<string> acction = this.doSomething;           
AsyncCallback callback = ia => Console.WriteLine($"到這計算完成");
acction.BeginInvoke("btnAsync", callback, null);

執行緒等待

//判斷IsCompleted狀態是否結束 如果還沒就讓主執行緒睡覺
while (!asyncResult.IsCompleted)
{
Thread.Sleep(200);
}
asyncResult.AsyncWaitHandle.WaitOne();//等待任務完成
asyncResult.AsyncWaitHandle.WaitOne(-1);//等待任務完成
asyncResult.AsyncWaitHandle.WaitOne(100);//等待任務完成,但最多等待100ms
acction.EndInvoke(asyncResult);//等待任務完成,可以取得委派的返回數值

EndInvoke 示範 (主動使用EndInvoke,可以線呈更好的重用)

Func<int> fuck = () =>
{
Thread.Sleep(2000);
return DateTime.Now.Day;
};
Console.WriteLine($"func.Invoke() ={fuck.Invoke()}");
IAsyncResult asyncResult1 = fuck.BeginInvoke(
r =>
{
Console.WriteLine(r.AsyncState);
}, "冰封的心");
Console.WriteLine($"func.EndInvoke(asyncResult1) = {fuck.EndInvoke(asyncResult1)}");

Task

3.0 Task 是基於ThreadPool Task增加了多個API

執行方式

Task.Run
Task.Run(() => this.doSomething("task1"));
Task工廠模式版本
TaskFactory taskFactory = Task.Factory;//4.0
taskFactory.StartNew(() => this.doSomething("task3"));
Task.Start
new Task(() => this.doSomething("task5")).Start();

Task阻塞

主程序的情況
List<Task> taskList = new List<Task>();
taskList.Add(Task.Run(() => this.doSomething("01")));
taskList.Add(Task.Run(() => this.doSomething("02")));
taskList.Add(Task.Run(() => this.doSomething("03")));
taskList.Add(Task.Run(() => this.doSomething("04")));
會卡介面的方式
  • WaitAny 方法會判斷 taskList中如果有其中一個執行緒結束,就會往下執行下面的程式
  • WaitAll 方法會判斷 taskList中全部的執行緒結束,才會往下執行下面的程式
//阻塞 等者某個任務完成後才會往下進行
Task.WaitAny(taskList.ToArray());//卡介面
//阻塞 等者全部任務完成後才會往下進行
Task.WaitAll(taskList.ToArray());//卡介面
不會卡介面的方式
WhenXXX.ContinueWith 的方式會在創造一條子執行緒,等待條件結束會在執行,
ContinueWith裡面的內容
Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"哈哈哈哈:{Thread.CurrentThread.ManagedThreadId}");
});

Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"部屬環境,測試完成 執行緒:{Thread.CurrentThread.ManagedThreadId}");
});

執行緒等待的方式 Sleep & Delay

Thread.Sleep 會卡介面

當前執行緒等待XX秒
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Thread.Sleep(2000);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);

Task.Delay 延遲 不會卡介面

使用做法
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task.Delay(2000).ContinueWith(t =>
{
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
});
類似的功能
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task.Run(() =>
{
Thread.Sleep(2000);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
});

Parallel

並行線程 在Task的基礎上做了封裝 4.5
Parallel 卡介面 主線程參與計算,節約了一個線程

執行方法

第一種
Parallel.Invoke(() => this.doSomething("test1"),
() => this.doSomething("test1"),
() => this.doSomething("test1"));
第二種
Parallel.For(0, 5, i => this.doSomething("第"+i));
第三種
Parallel.ForEach(new string[] { "1", "2", "3", "4", "5" },i =>this.doSomething(i));

設定最多執行緒數量

ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0, 5, i => this.doSomething("第" + i));

Break =>類似conntinue,Stop=> 類似break;

//Break  Stop  都不推荐用
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0, 100, parallelOptions, (i, state) =>
{
if (i == 2)
{
Console.WriteLine("Break,當前線呈結束");
state.Break();//當前線呈結束
return;//必须带上,才會釋放資源
}
if (i == 30)
{
Console.WriteLine("線呈Stop,結束");
state.Stop();//结束Parallel
return;//必须带上,才會釋放資源
}
this.Coding("當前參數", "Client" + i);
});
目前測試Break && Stop 看不出效果
Break 實際上結束了當前這個線呈,如果是主現成 等於Parallel都結束了
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 1;
Parallel.For(1, 100, (i, ParallelLoopState) =>
{
Console.WriteLine($"開始 i => {i} 主要執行續 => {Thread.CurrentThread.ManagedThreadId.ToString("00")}");

if (i == 5)
{
Console.WriteLine($"掰掰 i => {i} 主要執行續 => {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// 跳出當前執行單元
ParallelLoopState.Stop();
return;//不加return,可能會發生該程序資源未釋放。
}
Console.WriteLine($"結束 i => {i} 主要執行續 => {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
});

例外(異常)處理

TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>();
try
{
for (int i = 0; i < 20; i++)
{
string name = string.Format($"btnThreadCore_Click_{i}");
Action<object> act = t =>
{

Thread.Sleep(2000);
if (t.ToString().Equals("btnThreadCore_Click_11"))
{
throw new Exception(string.Format($"{t} 执行失败"));
}
if (t.ToString().Equals("btnThreadCore_Click_12"))
{
throw new Exception(string.Format($"{t} 执行失败"));
}
Console.WriteLine("{0} 执行成功", t);


};
taskList.Add(taskFactory.StartNew(act, name));
}
}
catch (AggregateException aex)
{
foreach (var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
雖然在多執行緒,外包try catch卻捕捉不到例外
📷
執行緒裡面的異常會被吞掉,因為已經郭離try catch的範圍了 使用waitAll 可以抓到多線呈裡面裡面的全部異常
TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>();
try
{
for (int i = 0; i < 20; i++)
{
string name = string.Format($"btnThreadCore_Click_{i}");
Action<object> act = t =>
{

Thread.Sleep(2000);
if (t.ToString().Equals("btnThreadCore_Click_11"))
{
throw new Exception(string.Format($"{t} 執行失敗"));
}
if (t.ToString().Equals("btnThreadCore_Click_12"))
{
throw new Exception(string.Format($"{t} 執行失敗"));
}
Console.WriteLine("{0} 執行成功", t);


};
taskList.Add(taskFactory.StartNew(act, name));
}
Task.WaitAll(taskList.ToArray());
}
catch (AggregateException aex)
{
foreach (var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
必須使用waitAll,才捕捉的到Exception,but會導致卡畫面使用者體驗上會有等待的感覺
📷
建議 執行緒裡面的action不允許出現Exception,自己處理好
for (int i = 0; i < 20; i++)
{
string name = string.Format($"btnThreadCore_Click_{i}");
Action<object> act = t =>
{
try
{
Thread.Sleep(2000);
if (t.ToString().Equals("btnThreadCore_Click_11"))
{
throw new Exception(string.Format($"{t} 执行失败"));
}
if (t.ToString().Equals("btnThreadCore_Click_12"))
{
throw new Exception(string.Format($"{t} 执行失败"));
}
Console.WriteLine("{0} 执行成功", t);
}
catch (Exception ex)
{
Console.WriteLine($"Exception:{ex.Message}");
}
};
taskList.Add(taskFactory.StartNew(act, name));
}
Task.WaitAll(taskList.ToArray());

執行續取消

可以透過CancellationTokenSource類別實作
//多个线程并发,某个失败后,希望通知别的线程,都停下来
//task是外部无法中止,Thread.Abort不靠谱,因为线程是OS的资源,无法掌控啥时候取消
//线程自己停止自己--公共的访问变量--修改它---线程不断的检测它(延迟少不了)
//CancellationTokenSource去标志任务是否取消 Cancel取消 IsCancellationRequested 是否已经取消了
//Token 启动Task的时候传入,那么如果Cancel了,这个任务会放弃启动,抛出一个异常

CancellationTokenSource cts = new CancellationTokenSource();//bool值 //bool flag = true;
for (int i = 0; i < 40; i++)
{
string name = string.Format("btnThreadCore_Click{0}", i);
Action<object> act = t =>
{
try
{
//if (cts.IsCancellationRequested)
//{
// Console.WriteLine("{0} 取消一个任务的执行", t);
//}
Thread.Sleep(2000);
if (t.ToString().Equals("btnThreadCore_Click11"))
{
throw new Exception(string.Format("{0} 执行失败", t));
}
if (t.ToString().Equals("btnThreadCore_Click12"))
{
throw new Exception(string.Format("{0} 执行失败", t));
}
if (cts.IsCancellationRequested)//检查信号量
{
Console.WriteLine("{0} 放弃执行", t);
return;
}
else
{
Console.WriteLine("{0} 执行成功", t);
}
}
catch (Exception ex)
{
cts.Cancel();
Console.WriteLine(ex.Message);
}
};
taskList.Add(taskFactory.StartNew(act, name, cts.Token));
}
Task.WaitAll(taskList.ToArray());
📷
在這裡 (1) 的cts因為一開始輸入參數為false 所以會跳出exception 被(2) 捕捉到,因此才會印出 工作已取消。

線呈臨時變數

因為i是全域變數,所以最後印出來的結果會是i = 5;
input:
for (int i = 0; i < 5; i++)
{
Task.Run(() =>
{
Thread.Sleep(100);
Console.WriteLine(i);
});
}
output:
5
5
5
5
5
修正方式:
i最后是5 全程就只有一个i 等着打印的时候,i == 5
k 全程有5个k 分别是0 1 2 3 4
如果k在外面宣告 全程就只有一个k,等着打印的时候,k == 4
for (int i = 0; i < 5; i++)
{
int k = i;
Task.Run(() =>
{
Thread.Sleep(100);
Console.WriteLine(k);
});
}

執行緒安全 lock

容易造成 資料錯誤的原因:
共用的變數:都能共同訪問的區域變數/全域變數/數據庫的一個值/硬碟文件
執行緒内部不共享的是安全
範例:
int TotalCountIn = 0;
for (int i = 0; i < 10000; i++)
{
TotalCountIn++;
}
Console.WriteLine($"TotalCountIn = {TotalCountIn}");
輸出結果會是:
TotalCountIn = 10000
如果改成用多執行緒的方式
int TotalCountIn = 0;
for (int i = 0; i < 10000; i++)
{
Task.Run(() =>
{
TotalCountIn++;
});
}
Console.WriteLine($"TotalCountIn = {TotalCountIn}");
輸出結果會是:
TotalCountIn = 8972
為什麼會出現這樣的情況呢?
📷

解法1

private 防止外面也去lock static 全场唯一 readonly不要改动 object表示引用
微軟推薦的方式 =>將要鎖住的內容包在lock裡面
private static readonly object btnThreadCore_Click_Lock = new object();
lock (btnThreadCore_Click_Lock)
{

}
範例:
private static readonly object btnThreadCore_Click_Lock = new object();
void Main()
{
List<Task> taskList = new List<Task>();
int TotalCountIn = 0;
List<int> IntList = new List<int>();
for (int i = 0; i < 10000; i++)
{
int newI = i;
taskList.Add(Task.Run(() =>
{
lock(btnThreadCore_Click_Lock)
{
TotalCountIn+=1;
IntList.Add(newI);
}
}));
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine($"TotalCountIn = {TotalCountIn}");
Console.WriteLine("IntList 總數量為 = " + IntList.Count());
}
輸出結果:
TotalCountIn = 10000
IntList 總數量為 = 10000
在這裡需要加上Task.WaitAll(taskList.ToArray()); 確保所有執行緒都執行完成,這樣顯示的結果才會是正確的

解法2 lock(this)

this form1的實體 每次實體化是不同的鎖,同一個實體是相同的鎖
但是這個實體別人也能訪問到,別人也能鎖住
lock(this)
{

}
範例:
void Main()
{
List<Task> taskList = new List<Task>();
int TotalCountIn = 0;
List<int> IntList = new List<int>();
for (int i = 0; i < 10000; i++)
{
int newI = i;
taskList.Add(Task.Run(() =>
{
lock(this)
{
TotalCountIn+=1;
IntList.Add(newI);
}
}));
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine($"TotalCountIn = {TotalCountIn}");
Console.WriteLine("IntList 總數量為 = " + IntList.Count());
}

解法3 Monitor

將程式包在Monitor裡面就跟lock一樣
Monitor.Enter(btnThreadCore_Click_Lock);

要執行的程式

Monitor.Exit(btnThreadCore_Click_Lock);
範例:
private static readonly object btnThreadCore_Click_Lock = new object();
void Main()
{
List<Task> taskList = new List<Task>();
int TotalCountIn = 0;
List<int> IntList = new List<int>();
for (int i = 0; i < 10000; i++)
{
int newI = i;
taskList.Add(Task.Run(() =>
{
Monitor.Enter(btnThreadCore_Click_Lock);
TotalCountIn+=1;
IntList.Add(newI);
Monitor.Exit(btnThreadCore_Click_Lock);
}));
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine($"TotalCountIn = {TotalCountIn}");
Console.WriteLine("IntList 總數量為 = " + IntList.Count());
}

解法4

使用 安全對列 ConcurrentQueue 一個執行緒去完成操作
注意:
值類型不行lock
int m = 3 + 2;
lock (m) { }//值類型不能lock
只能鎖引用類型,占用這個引用鏈結 不要用string 因為享元
string teacher = "Eleven";
string teacherVip = "Eleven";
lock (teacher)
{
}
lock (teacherVip)
{
}

結論

lock 解决,因为只有一个线程可以进去,没有并发,所以解决了问题 但是牺牲了性能,所以要尽量缩小lock的范围
不要衝突--數據拆分,避免衝突

參考資料

本篇已同步發表至個人部落格
https://moushih.com/2022ithome20/
鐵人賽文章
為什麼會看到廣告
avatar-img
8會員
39內容數
我是這個部落格的作者,喜歡分享有關投資 💰、軟體開發 💻、占卜 🔮 和虛擬貨幣 🚀 的知識和經驗。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
一代軍師 的其他內容
介紹 📷 定義 處理序(Process) (大陸:進程): 一個程序運行時,占用全部計算資源的總和 執行緒(Thread) (大陸:線程):是作業系統能夠進行運算排程的最小單位。 大部分情況下,它被包含在行程之中,是行程中的實際運作單位。 C#多線程和異步(一)——基本概念和使用方法 執行緒帶來的
介紹 計算機架構相關名詞 📷 中央處理器 (CPU)Central Processing Unit Processors (處理器) Sockets (實體插槽) Cores (實體核心) Logical processors (邏輯核心) 超執行緒(HT)Hyper-Threading Tec
Array 在記憶體中連續分配,而且元素類型是一樣的,長度不變 優點:讀取快,可以使用座標訪問 缺點:新增、刪除慢 記憶體: 📷 範例程式碼: ArrayList 不定長度,在記憶體中連續分配的,元素沒有類型限制,任何元素都是當成object處理,如果是值類型,會有裝箱的操作 優點:讀取快 缺點:
介紹 這章節純看智商 不可逆加密:原文加密後變成密文,但密文沒辦法解密文回原文 可逆加密:原文加密過後的密文,可以在將密文解密回原文 對稱:表示加解密是否使用同一個key MD5 不可逆加密 MD5 使用的命名空間是 System.Security.Cryptography MD5是一種公開的算法
環境安裝 這邊可以先安裝Expression Tree Visualizer工具 Viusla studio 2019 安裝方式: 檔案(ExpressionTreeVisualizer.2019)下載完之後,將檔案複製到此目錄: C:\Program Files (x86)\Microsoft V
環境準備 準備用測試資料 語法說明 Where 應用場景:過濾、查詢等功能 說明:與SQL命令中的where功能相似,都是過濾範圍內的數值 例如:使用where篩選,年紀大於30的同學 First 應用場景:篩選出第一筆資料,但資料如果是空的會跳Exception 說明:返回集合中的第一個元素,其實
介紹 📷 定義 處理序(Process) (大陸:進程): 一個程序運行時,占用全部計算資源的總和 執行緒(Thread) (大陸:線程):是作業系統能夠進行運算排程的最小單位。 大部分情況下,它被包含在行程之中,是行程中的實際運作單位。 C#多線程和異步(一)——基本概念和使用方法 執行緒帶來的
介紹 計算機架構相關名詞 📷 中央處理器 (CPU)Central Processing Unit Processors (處理器) Sockets (實體插槽) Cores (實體核心) Logical processors (邏輯核心) 超執行緒(HT)Hyper-Threading Tec
Array 在記憶體中連續分配,而且元素類型是一樣的,長度不變 優點:讀取快,可以使用座標訪問 缺點:新增、刪除慢 記憶體: 📷 範例程式碼: ArrayList 不定長度,在記憶體中連續分配的,元素沒有類型限制,任何元素都是當成object處理,如果是值類型,會有裝箱的操作 優點:讀取快 缺點:
介紹 這章節純看智商 不可逆加密:原文加密後變成密文,但密文沒辦法解密文回原文 可逆加密:原文加密過後的密文,可以在將密文解密回原文 對稱:表示加解密是否使用同一個key MD5 不可逆加密 MD5 使用的命名空間是 System.Security.Cryptography MD5是一種公開的算法
環境安裝 這邊可以先安裝Expression Tree Visualizer工具 Viusla studio 2019 安裝方式: 檔案(ExpressionTreeVisualizer.2019)下載完之後,將檔案複製到此目錄: C:\Program Files (x86)\Microsoft V
環境準備 準備用測試資料 語法說明 Where 應用場景:過濾、查詢等功能 說明:與SQL命令中的where功能相似,都是過濾範圍內的數值 例如:使用where篩選,年紀大於30的同學 First 應用場景:篩選出第一筆資料,但資料如果是空的會跳Exception 說明:返回集合中的第一個元素,其實
你可能也想看
Google News 追蹤
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
這篇內容,將會講解什麼是「do until」,以及與「do until」相關的知識。包括do until的簡介、break、continue。
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
※ 非同步概念總複習 為什麼要使用 Promise? 在 JavaScript 開發中,處理非同步操作是常見需求,涉及如文件讀寫、數據庫查詢或網路請求等耗時任務。傳統的回調方式可能導致代碼結構混亂,稱為「回調地獄」,難以維護和理解。 Promise 是解決這問題的方法。它是一個物件(objec
Thumbnail
看到標題的朋友可能會覺得奇怪, 我們常常看到的不就是time.sleep嗎? 怎麼又多出了asyncio.sleep呢? 這兩者究竟差異在哪邊呢? 我們都知道sleep就是睡眠的意思, 那麼在程式的運作上就是等待, 等待一段時間之後繼續完成任務, time.sleep的部份很好理解, 就是在該段程
認識 async/await基本概念: async 的本質是 promise 的語法糖 ,只要 function 標記為 async,就表示裡頭可以撰寫 await 的同步語法,而 await 顧名思義就是「等待」,它會確保一個 promise 物件都解決 ( resolve ) 或出錯 ( re
什麼是 Promise.all? 在有多個 Promise 的時候,使用 Promise.all 可以確保「所有的 Promise 都執行完以後,才進入 then」。 Promise.all 語法結構: Promise.all 接受的參數是陣列形式。 什麼時候要使用 Promise.all?
※ Promise基本介紹 什麼是 Promise? Promise 是 JavaScript 的一個構造函式,用於創建表示非同步操作的物件實例。使用 new Promise() 時,你會創建一個包含非同步操作的實例,這個實例可以透過其繼承的方法如 then(), catch(), 和 fina
※ 同步概念: 單純地「由上而下」執行程式碼,而且一次只執行一件事,也就是「按順序執行,一個動作結束才能切換到下一個」。缺點是你需要「等待」事情執行完畢,才能繼續往下走。 ※ 非同步概念: 盡可能讓主要的執行程序不需要停下來等待,若遇到要等待的事情,就發起一個「非同步處理」,讓主程序繼續執行,
Thumbnail
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
非同步程式設計(Asynchronous programming) 或是簡單的稱之為 async,它是一種並發程式模型(concurrent programming model),其目的就是讓多個任務能同時在作業系統的執行緒上執行,並透過 async/.await 保留同步。
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
這篇內容,將會講解什麼是「do until」,以及與「do until」相關的知識。包括do until的簡介、break、continue。
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
※ 非同步概念總複習 為什麼要使用 Promise? 在 JavaScript 開發中,處理非同步操作是常見需求,涉及如文件讀寫、數據庫查詢或網路請求等耗時任務。傳統的回調方式可能導致代碼結構混亂,稱為「回調地獄」,難以維護和理解。 Promise 是解決這問題的方法。它是一個物件(objec
Thumbnail
看到標題的朋友可能會覺得奇怪, 我們常常看到的不就是time.sleep嗎? 怎麼又多出了asyncio.sleep呢? 這兩者究竟差異在哪邊呢? 我們都知道sleep就是睡眠的意思, 那麼在程式的運作上就是等待, 等待一段時間之後繼續完成任務, time.sleep的部份很好理解, 就是在該段程
認識 async/await基本概念: async 的本質是 promise 的語法糖 ,只要 function 標記為 async,就表示裡頭可以撰寫 await 的同步語法,而 await 顧名思義就是「等待」,它會確保一個 promise 物件都解決 ( resolve ) 或出錯 ( re
什麼是 Promise.all? 在有多個 Promise 的時候,使用 Promise.all 可以確保「所有的 Promise 都執行完以後,才進入 then」。 Promise.all 語法結構: Promise.all 接受的參數是陣列形式。 什麼時候要使用 Promise.all?
※ Promise基本介紹 什麼是 Promise? Promise 是 JavaScript 的一個構造函式,用於創建表示非同步操作的物件實例。使用 new Promise() 時,你會創建一個包含非同步操作的實例,這個實例可以透過其繼承的方法如 then(), catch(), 和 fina
※ 同步概念: 單純地「由上而下」執行程式碼,而且一次只執行一件事,也就是「按順序執行,一個動作結束才能切換到下一個」。缺點是你需要「等待」事情執行完畢,才能繼續往下走。 ※ 非同步概念: 盡可能讓主要的執行程序不需要停下來等待,若遇到要等待的事情,就發起一個「非同步處理」,讓主程序繼續執行,
Thumbnail
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
非同步程式設計(Asynchronous programming) 或是簡單的稱之為 async,它是一種並發程式模型(concurrent programming model),其目的就是讓多個任務能同時在作業系統的執行緒上執行,並透過 async/.await 保留同步。