Lover Service is created : a40404ce-51c7-4922-8991-b1b28a601d18 Service 0 ID: a40404ce-51c7-4922-8991-b1b28a601d18 Service 1 ID: a40404ce-51c7-4922-8991-b1b28a601d18 Service 2 ID: a40404ce-51c7-4922-8991-b1b28a601d18
Lover Service is created : 3fdba22c-157b-4c96-8da0-9d9d0e123518 Lover Service is created : 502c1f4b-c034-402a-9a56-a4cfc4dabfe8 Lover Service is created : 1afdf1da-860a-4a03-9f9d-7ca9a26cb6e8 Service 0 ID: 3fdba22c-157b-4c96-8da0-9d9d0e123518 Service 1 ID: 502c1f4b-c034-402a-9a56-a4cfc4dabfe8 Service 2 ID: 1afdf1da-860a-4a03-9f9d-7ca9a26cb6e8
Parallel.For(0, 10, index => { var svc = serviceProvider.GetRequiredService<FindLoverInterface>(); System.Console.WriteLine($"Thread {index}: Service ID = {svc.Id}"); });
Singleton
1 2 3 4 5 6 7 8 9 10
Thread 1: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 2: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 3: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 0: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 5: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 7: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 6: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 4: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 8: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d Thread 9: Service ID = b428f9d9-02e3-4378-8ebc-c3dd8c32768d
✔ 結論:大家都拿到同一個實例。就像大家共用一支 Wi-Fi,只是大家下載東西的速度可能不一樣。
Scoped(未開 scope):意外變成 Singleton
1 2 3 4 5 6 7 8 9 10 11
Lover Service is created : 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 1: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 3: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 6: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 7: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 2: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 5: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 0: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 4: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 9: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8 Thread 8: Service ID = 60851d37-7578-4ad6-bd21-f46daffe85f8
Parallel.For(0, count, i => { usingvar scope = serviceProvider.CreateScope(); var svc = scope.ServiceProvider.GetRequiredService<FindLoverInterface>(); System.Console.WriteLine($"Thread {i}: Service ID = {svc.Id}"); });
Lover Service is created : 0827b278-cc43-4bdd-a521-fbbc0c56b10c Lover Service is created : 240ed452-9d3e-4a18-9a84-df042f08cf71 Lover Service is created : e752bb4f-6be7-4984-a3cc-1a638bcc879c Lover Service is created : 002d0041-43ab-413f-95b4-93e82212a297 Lover Service is created : 6daab032-e1b7-4ae4-b8f4-267b385f801c Lover Service is created : e96d4ed7-219d-4d2b-9ef3-8da729e57174 Lover Service is created : ba899eab-d4d8-4ba7-8a97-8fc8e5b06db1 Lover Service is created : 5fcbdfa6-dfc1-4975-a0fe-4eed167aac94 Lover Service is created : 8bd944a1-4bce-4c20-944e-6e143166f61b Lover Service is created : 996e3373-77ce-4e88-ae18-e183d17d25f6 Lover Service is created : 4b791f48-25ca-4378-8566-89d8d1a7190d Thread 4: Service ID = 002d0041-43ab-413f-95b4-93e82212a297 Thread 6: Service ID = 240ed452-9d3e-4a18-9a84-df042f08cf71 Thread 9: Service ID = e96d4ed7-219d-4d2b-9ef3-8da729e57174 Thread 7: Service ID = e752bb4f-6be7-4984-a3cc-1a638bcc879c Thread 0: Service ID = 6daab032-e1b7-4ae4-b8f4-267b385f801c Thread 1: Service ID = 996e3373-77ce-4e88-ae18-e183d17d25f6 Thread 3: Service ID = 8bd944a1-4bce-4c20-944e-6e143166f61b Thread 8: Service ID = ba899eab-d4d8-4ba7-8a97-8fc8e5b06db1 Thread 2: Service ID = 5fcbdfa6-dfc1-4975-a0fe-4eed167aac94 Thread 5: Service ID = 4b791f48-25ca-4378-8566-89d8d1a7190d
Lover Service is created : 7fa7e822-e2e5-49f3-8128-410fe656d04f Lover Service is created : ba767f56-ef68-4bb6-ae60-988adc5bc5d4 Lover Service is created : 5c0a8585-cb7f-4829-ba44-5e3273dbc161 Lover Service is created : 3a2410ab-5043-482e-9fd5-00fb73c66d40 Lover Service is created : cbcbb913-2549-4dc8-b064-4115f2eaf8a6 Lover Service is created : 9746a516-d4ec-4f9d-9106-ed598eed2ebf Lover Service is created : ce3e602d-f345-4143-a110-15c01eebf4c4 Thread 2: Service ID = ba767f56-ef68-4bb6-ae60-988adc5bc5d4 Thread 9: Service ID = 5c0a8585-cb7f-4829-ba44-5e3273dbc161 Thread 3: Service ID = 3a2410ab-5043-482e-9fd5-00fb73c66d40 Lover Service is created : 5b7e1606-8bd2-41dc-9a0d-3992ddbc10de Thread 1: Service ID = cbcbb913-2549-4dc8-b064-4115f2eaf8a6 Thread 5: Service ID = 5b7e1606-8bd2-41dc-9a0d-3992ddbc10de Thread 0: Service ID = ce3e602d-f345-4143-a110-15c01eebf4c4 Lover Service is created : 030c489b-0da8-46b2-bbbf-78fab6b5e8d3 Lover Service is created : b0177ff6-8806-4113-98b0-0ddac7024b38 Lover Service is created : bc65f658-58d0-4176-b3c1-95f2e87091e0 Thread 6: Service ID = 9746a516-d4ec-4f9d-9106-ed598eed2ebf Thread 4: Service ID = 030c489b-0da8-46b2-bbbf-78fab6b5e8d3 Thread 7: Service ID = b0177ff6-8806-4113-98b0-0ddac7024b38 Thread 8: Service ID = bc65f658-58d0-4176-b3c1-95f2e87091e0
publicclassFindLover : FindLoverInterface { private List<string> _data = new List<string>(); public Guid Id { get; } = Guid.NewGuid();
publicFindLover() { System.Console.ForegroundColor = ConsoleColor.Cyan; System.Console.WriteLine($"Lover Service is created : {Id}"); System.Console.ResetColor(); }
publicvoidAddSomthing(int addCount) { _data.Add($"Data from thread {addCount}"); } publicvoidPrintResult(int expected) { System.Console.ForegroundColor = ConsoleColor.Yellow; System.Console.WriteLine($"Expected count: {expected}"); System.Console.WriteLine($"Actual count: {_data.Count}"); System.Console.ResetColor(); if (_data.Count != expected) { System.Console.ForegroundColor = ConsoleColor.Red; System.Console.WriteLine("Data is corrupted due to lack of thread safety!"); System.Console.ResetColor(); } else { System.Console.ForegroundColor = ConsoleColor.Green; System.Console.WriteLine("Data integrity is correct (by luck or protection)"); System.Console.ResetColor(); } } }
執行程式
1 2 3 4 5 6 7 8 9
var svc = serviceProvider.GetRequiredService<FindLoverInterface>(); int count = 10_000;
Parallel.For(0, count, i => { svc.AddSomthing(count); });
svc.PrintResult(count);
結果
1 2 3 4
Lover Service is created : 28bb54c9-3c90-4857-bdc3-8bc938043c15 Unhandled exception. System.AggregateException: One or more errors occurred. (Source array was not long enough. Check the source index, length, and the array's lower bounds. (Parameter 'sourceArray')) ---> System.ArgumentException: Source array was not long enough. Check the source index, length, and the array's lower bounds. (Parameter 'sourceArray') at System.Array.CopyImpl(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
👉 這是典型的執行緒安全問題,因為 List 在還沒長好(resize 的中途)時,其他執行緒就跑來塞資料,導致「認知不一致」,進而拋出例外。
為什麼會這樣?
List 不是執行緒安全的結構。它內部有一個陣列 _items[],當容量不夠時會觸發 Resize(),此時可能產生陣列搬移(Array.Copy)。若這個過程被其他執行緒「插隊使用」,就會造成 IndexOutOfRange、ArgumentException 等錯誤。