SQL Server PARTITION BY 分割分組語法

前言

最近處理到一些複雜需求,使用到了PARTITION BY。
於是記錄一下PARTITION BY的用法。
主要是能在分組時取得第一筆資料、與分組有關的操作。

PARTITION BY

Divides the query result set into partitions. The window function is applied to each partition separately and computation restarts for each partition.

PARTITION BY 可將查詢結果集分成幾個資料分割。

語法:

1
OVER ( [ PARTITION BY value_expression ] [ order_by_clause ] )  

實作

目標:要取得每個以UserId分組的第一筆資料

資料表:[DBO].[TODOS]

首先先使用PARTITION製造出分割出群組編號

1
2
3
4
5
SELECT 
ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY ID) ROW_ID,
*
FROM
[DBO].[TODOS]

可以見到ROW_ID出現在列表中,即代表這是這個UserId組的第幾筆資料。
依序為:
UserId為1的第1筆資料
UserId為3的第1筆資料
UserId為3的第2筆資料
UserId為3的第3筆資料
UserId為4的第1筆資料
UserId為5的第1筆資料

再來只要把這結果集外部包一個搜尋,使用條件就能拿到第一筆資料,如下設定:
ROW_ID為1代表取得每個分組的第一筆資料。

1
2
3
4
5
6
7
8
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY ID) ROW_ID,
*
FROM
[DBO].[TODOS]
) TEMP
WHERE TEMP.ROW_ID = 1

最終成功拿到每個UserId分組的第一筆資料

參考資料

C# LINQ JOIN 函式效果

前言

因為平時都是寫lambda寫法的LINQ,而在近期看到函式方式的寫法,所以紀錄一下作法。

JOIN函式定義

1
2
3
4
5
6
7
8
public static System.Collections.Generic.IEnumerable<TResult> 
Join<TOuter,TInner,TKey,TResult> (
this System.Collections.Generic.IEnumerable<TOuter> outer,
System.Collections.Generic.IEnumerable<TInner> inner,
Func<TOuter,TKey> outerKeySelector,
Func<TInner,TKey> innerKeySelector,
Func<TOuter,TInner,TResult> resultSelector,
System.Collections.Generic.IEqualityComparer<TKey>? comparer);

參數部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
outer
IEnumerable<TOuter>
要聯結的第一個序列。

inner
IEnumerable<TInner>
要加入第一個序列的序列。

outerKeySelector
Func<TOuter,TKey>
用來從第一個序列各個項目擷取聯結索引鍵的函式。

innerKeySelector
Func<TInner,TKey>
用來從第二個序列各個項目擷取聯結索引鍵的函式。

resultSelector
Func<TOuter,TInner,TResult>
用來從兩個相符項目建立結果項目的函式。

comparer
IEqualityComparer<TKey>
用來雜湊及比較索引鍵的 IEqualityComparer<T>。

實作

簡單來講就是拿主表資料去JOIN另一張關聯表,而x、y則是塞進去的key值。
在這裡以User為主表,UserDetail為關聯表。
原本4筆資料的User,經過與UserDetail JOIN關聯,於是剩下兩筆資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace JoinSample
{

public class User
{
public int Id { get; set; }
public string Name { get; set; }
}

public class UserDetail
{
public int UserId { get; set; }
public string PhoneNumber { get; set; }
}


public class UserData
{
public int Id { get; set; }

public string UserName { get; set; }
public string PhoneNumber { get; set; }
}

internal class Program
{
static void Main(string[] args)
{
var users = new List<User>
{
new User
{
Id =1,Name="大雄",
},
new User
{
Id =2,Name="多拉A夢",
},
new User
{
Id =3,Name="胖虎",
},
new User
{
Id =4,Name="小夫",
}
};

var userDetails = new List<UserDetail> {
new UserDetail{ UserId=1,PhoneNumber="0911111111"},
new UserDetail{ UserId=2,PhoneNumber="0922222222"}
};

var userData = users.Join(
userDetails,
x => x.Id,
y => y.UserId,
(x, y) => new UserData
{
Id = x.Id,
PhoneNumber = y.PhoneNumber,
UserName = x.Name
});

foreach (var item in userData)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.UserName);
Console.WriteLine(item.PhoneNumber);
}
}
}
}

output:

1
2
3
4
5
6
1
大雄
0911111111
2
多拉A夢
0922222222

參考資料

[Day7]C#建立不會停止的背景Task

前言

在上回 Post not found: Task運行處理-Run、Start、RunSynchronously-C-SyncAndAsync [Day6]Task運行處理(Run、Start、RunSynchronously) ,我們學習了Task的各種啟動方式。
而今回主要來撰寫不會停止的背景Task。

實作

不終止的非同步事件 ex:多個while(true)常駐。

主要使用以下的模板去製作常駐程式:

1
2
3
4
5
6
7
var endlessTask = Task.Run(async () =>
{
while (true)
{
// Todo
}
});

簡單來說就是開一個異步的Task讓他跑即可。

在以下的範例中endlessTask1、endlessTask2會不停的印出資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;
using System.Threading.Tasks;

namespace EndlessTaskAsync
{
class Program
{
/// <summary>
/// 主程式
/// </summary>
/// <returns></returns>
public static async Task Main()
{
var endlessTask1 = EndlessTask(1);
var endlessTask2 = EndlessTask(2);

await PreventToStop();
}

/// <summary>
/// 製作無止盡的 while task
/// </summary>
/// <param name="number">編號</param>
/// <returns></returns>
private static Task EndlessTask(int number)
{
Console.WriteLine("Start EndlessTask" + number);
var endlessTask = Task.Run(async () =>
{
while (true)
{
Console.WriteLine("EndlessTask" + number);
await Task.Delay(100);
}
});
return Task.CompletedTask;
}

/// <summary>
/// 避免視窗關閉,使用ReadKey();
/// </summary>
/// <returns></returns>
private static Task PreventToStop()
{
Console.ReadKey();
return Task.CompletedTask;
}
}
}

運行結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2

直到關掉程式都會一直印。

總結

在這回中練習了背景常駐的Task,通常會在監聽某個請求while中使用。
如果是以目前處理過的code,就是在socket處理上會大量使用。

專案存庫:
https://github.com/yuhsiang237/EndlessTaskAsync

C# Tuple實名、匿名用法

最近在寫資料時需要回傳多筆數,但在資料單純、沒特別的邏輯的情況下不想再建立一個Model回傳,這時就可以使用Tuple返回元組類型。

以下為匿名、實名的兩種Tuple寫法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace TupleSample
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(String.Concat(GetUser1().Id, GetUser1().Name));
Console.WriteLine(String.Concat(GetUser2().Item1, GetUser2().Item2));
}

static (int Id, string Name) GetUser1()
{
return (5, "王小明");
}


static Tuple<int, string> GetUser2()
{
return Tuple.Create(5, "王小明");
}
}
}

output

1
2
5王小明
5王小明

總結

當返回值較為單純時可以使用,如2~3個返回值。

參考資料

https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/builtin-types/value-tuples

[Day6]Task運行處理(Run、Start、RunSynchronously)

前言

在上回 Post not found: Task等待處理-Wait、WaitAll、WaitAny、WaitAsync、WhenAll、WhenAny-C-SyncAndAsync [Day5]Task等待處理(Wait、WaitAll、WaitAny、WaitAsync、WhenAll、WhenAny) - C# SyncAndAsync ,我們使用了Task來測試等待的效果,而這回主要探討的是執行運行。

  • Task.Run:將指定在 ThreadPool 執行工作排入佇列,並傳回該工作的工作或 Task 控制代碼。
  • Task.Start:啟動 Task,並排定它在目前的 TaskScheduler 執行。
  • Task.RunSynchronously:在目前的 Task 上同步執行 TaskScheduler。

讓一個Task運行的兩種做法

其實Task.Run、Task.Start都是能達到一樣的結果,只是寫法一個是分兩段,一個是一氣呵成。

1.第一種用new Task搭配Task.Start,必須寫兩段。好處是可以先建立了,再決定哪時啟用。

1
2
3
4
5
public static void Main(string[] args)
{
Task task = new Task(() => Console.WriteLine("task"));
task.Start();
}

2.第二種用Run,一氣呵成。執行當下就直接運行。

1
2
3
4
5
6
7
public static void Main(string[] args)
{
Task Task = Task.Run(() =>
{
Console.WriteLine("task");
});
}

因此以上兩種用法Task.Run、Task.Start的差別已經清楚了。
再來則是RunSynchronously用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
public static void Main()
{
Console.WriteLine("Application executing on thread {0}",
Thread.CurrentThread.ManagedThreadId);
var asyncTask = Task.Run(() => {
Console.WriteLine("Task {0} (asyncTask) executing on Thread {1}",
Task.CurrentId,
Thread.CurrentThread.ManagedThreadId);
long sum = 0;
for (int ctr = 1; ctr <= 1000000; ctr++)
sum += ctr;
return sum;
});
var syncTask = new Task<long>(() => {
Console.WriteLine("Task {0} (syncTask) executing on Thread {1}",
Task.CurrentId,
Thread.CurrentThread.ManagedThreadId);
long sum = 0;
for (int ctr = 1; ctr <= 1000000; ctr++)
sum += ctr;
return sum;
});
syncTask.RunSynchronously();
Console.WriteLine();
Console.WriteLine("Task {0} returned {1:N0}", syncTask.Id, syncTask.Result);
Console.WriteLine("Task {0} returned {1:N0}", asyncTask.Id, asyncTask.Result);
}
}

執行結果:

1
2
3
4
5
6
Application executing on thread 1
Task 2 (syncTask) executing on Thread 1
Task 1 (asyncTask) executing on Thread 4

Task 2 returned 500,000,500,000
Task 1 returned 500,000,500,000

官方給的解釋:
在這兩種情況下,工作都會執行相同的 lambda 運算式,以顯示工作識別碼和工作執行所在之執行緒的識別碼。此工作會計算介於1到1000000之間的整數總和。 如範例的輸出所示,藉由呼叫方法來執行的工作 RunSynchronously 會在應用程式執行緒上執行,而非同步工作則不是。

簡單來說就是:RunSynchronously會在主執行序上面跑。而非同步的則會在其他執行序。

總結

在這回中可以知道讓Task執行有哪幾種作法。

參考資料

[Day5]Task等待處理(Wait、WaitAll、WaitAny、WaitAsync、WhenAll、WhenAny) - C# SyncAndAsync

前言

在上回 Post not found: 使用Task撰寫第一個非同步程式-C-SyncAndAsync [Day4]使用Task撰寫第一個非同步程式 - C# SyncAndAsync ,我們使用了Task來撰寫第一隻非同步的程式。
而在這回將會著重在等待方面。

Task提供以下語法能夠等待:Wait、WaitAll、WaitAny、WaitAsync、WhenAll、WhenAny。

  • Task.Wait:等候 Task 完成執行。
  • Task.WaitAll:等待所有提供的 Task 物件完成執行。
  • Task.WaitAny:等候任一提供的 Task 物件完成執行。
  • Task.WaitAsync:取得 Task 當此 Task 完成或指定的超時時間過期時將完成的。(ps.是.NET6, 7 Preview 1才支援的新語法,目前是用.net core 3.1所以先不做範例)
  • Task.WhenAll:建立當所有提供的工作完成時才會完成的工作。
  • Task.WhenAny:建立當任何一個提供的工作完成時才會完成的工作。

這麼看來,使用Wait、When差別好像很難分清楚?再稍微比較一下:

Task.WhenAll Task.WaitAll
調用時阻塞該線程 不會
返回值 Task
備註 可以用返回的Task去檢查是否完成

此外,Task.WhenAll()也能用前面加await的語法去製造出阻塞。

1
await Task.WhenAll()

因此在使用上,能夠全部使用When再搭配await去組合出Wait的效果。

實作測試

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace TaskWaitHandle
{
public class Program
{
public static void Main(string[] args)
{
TaskWaitTest();

TaskWaitAllTest();
TaskWhenAllTest();

TaskWaitAnyTest();
TaskWhenAnyTest();
}

/// <summary>
/// 測試Task.WaitAny
/// </summary>
public static void TaskWaitAnyTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();


var tasks = new List<Task> { DelayTime(5000), DelayTime(3000), DelayTime(2000) };
Task.WaitAny(tasks.ToArray());

string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine(nameof(TaskWaitAnyTest) + " : 一共花費:" + second + "秒");
}

/// <summary>
/// 測試Task.WhenAny
/// </summary>
public static void TaskWhenAnyTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();


var tasks = new List<Task> { DelayTime(5000), DelayTime(3000), DelayTime(2000) };
var t = Task.WhenAny(tasks);

string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine(nameof(TaskWhenAnyTest) + " : 一共花費:" + second + "秒");
}

/// <summary>
/// 測試Task.WhenAll
/// </summary>
public static void TaskWhenAllTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();


var tasks = new List<Task> { DelayTime(5000), DelayTime(3000), DelayTime(2000) };
var t = Task.WhenAll(tasks);

string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine(nameof(TaskWhenAllTest) + " : 一共花費:" + second + "秒");
}

/// <summary>
/// 測試Task.WaitAll
/// </summary>
public static void TaskWaitAllTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();


var tasks = new List<Task> { DelayTime(5000), DelayTime(3000), DelayTime(2000) };
Task.WaitAll(tasks.ToArray());

sw.Stop();
string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine(nameof(TaskWaitAllTest) + " : 一共花費:" + second + "秒");
}

/// <summary>
/// 測試Task.Wait
/// </summary>
public static void TaskWaitTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();


Task t = DelayTime(5000);
t.Wait();
sw.Stop();


string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine(nameof(TaskWaitTest) + " : 一共花費:" + second + "秒");
}

/// <summary>
/// 停止一段時間
/// </summary>
/// <param name="millseconds">停止毫秒</param>
/// <returns></returns>
public static async Task DelayTime(int millseconds)
{
await Task.Delay(millseconds);
}
}
}

執行完結果:

1
2
3
4
5
TaskWaitTest : 一共花費:5.0991762秒
TaskWaitAllTest : 一共花費:5.017742599999999秒
TaskWhenAllTest : 一共花費:0.0008574秒
TaskWaitAnyTest : 一共花費:2.0228913秒
TaskWhenAnyTest : 一共花費:0.0006043秒

可以見到When不會阻塞所以直接被帶過,而Wait造成阻塞。

總結

可以知道Task使用Wait會阻塞,When不會阻塞。
而使用When可以再之後去檢查該返回值是否完成。

至於如果想讓When阻塞,就使用await即可。
所以總結是:When搭await可以組出所有阻塞/非阻塞,因此一路組合技用到底即可,而Wait可以擺一邊放置了。

參考資料

[Day4]使用Task撰寫第一個非同步程式 - C# SyncAndAsync

前言

在上回 Post not found: C-中Task與Thread比較-C-SyncAndAsync [Day3]C#中Task與Thread比較 - C# SyncAndAsync ,比較了Task、Thread,而這回主要會以Task撰寫第一個非同步程式。

什麼是Task

Task類別代表不會傳回值,而且通常會以非同步方式執行的單一作業。 Task物件是工作架構非同步模式的其中一個核心元件,第一次是在 .NET Framework 4 中引進。 由於物件所執行的工作 Task 通常會線上程集區執行緒上以非同步方式執行,而不是在主應用程式執行緒上同步執行,因此您可以使用 Status 屬性以及 IsCanceled 、 IsCompleted 和 IsFaulted 屬性來判斷工作的狀態。 最常見的情況是使用 lambda 運算式來指定工作要執行的工作。

針對傳回值的作業,您可以使用 Task<TResult> 類別。

需求

我們有五件事情分別如下:

  1. 起床
  2. 打遊戲
  3. 聽音樂
  4. 吃零食
  5. 睡覺

而我們預計起床->同時執行打遊戲、聽音樂、吃零食->睡覺。
整體的順序會如下圖:

程式撰寫

再來我們快速撰寫一下程式碼。

我們將以下的事情都設定一個執行的時間:

  1. 起床,2秒
  2. 打遊戲,5秒
  3. 聽音樂,4秒
  4. 吃零食,4秒
  5. 睡覺,3秒

為了要使程式能夠等待,因此我們在函式上需要加入async,才能再裡面寫await。(不然只能用後面加上.Wait()的作法,有點鱉就是)

我在前後都加上了Stopwatch碼表,用來計時,如果照理論,那完成時間是10秒。
因為2~4項是併發異步執行只要取最高的打遊戲。
即:2+5+3=10

在每個事情裡面使用
await Task.Delay(5000);
去設定每件事情做的時間

21~24行則呼叫事情,並且把它加入List。
利用await Task.WhenAll去等待所有List中Task執行完畢後才執行接下來的事情。

程式碼放置庫:https://github.com/yuhsiang237/TaskAsync

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace TaskAsync
{
public class Program
{
/// <summary>
/// 主程式
/// </summary>
/// <returns></returns>
public static async Task Main()
{
Stopwatch sw = new Stopwatch();
sw.Start();

await WakeUpAsync();

IList<Task> tasks = new List<Task>();
tasks.Add(PlayGameAsync());
tasks.Add(ListenMusicAsync());
tasks.Add(EatSnackAsync());

await Task.WhenAll(tasks);

await GoToBedSleepAsync();

sw.Stop();
string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine("一共花費:" + second + "秒");
}

/// <summary>
/// 模擬打遊戲
/// </summary>
/// <returns></returns>
private static async Task PlayGameAsync()
{
Console.WriteLine("打遊戲");
await Task.Delay(5000);
}

/// <summary>
/// 模擬聽音樂
/// </summary>
/// <returns></returns>
private static async Task ListenMusicAsync()
{
Console.WriteLine("聽音樂");
await Task.Delay(4000);
}

/// <summary>
/// 模擬吃零食
/// </summary>
/// <returns></returns>
private static async Task EatSnackAsync()
{
Console.WriteLine("吃零食");
await Task.Delay(4000);
}

/// <summary>
/// 模擬起床
/// </summary>
/// <returns></returns>
private static async Task WakeUpAsync()
{
Console.WriteLine("起床");
await Task.Delay(2000);
}

/// <summary>
/// 模擬睡覺
/// </summary>
/// <returns></returns>
private static async Task GoToBedSleepAsync()
{
Console.WriteLine("睡覺");
await Task.Delay(3000);
}
}
}

執行結果:

1
2
3
4
5
6
起床
打遊戲
聽音樂
吃零食
睡覺
一共花費:10.1614089秒

運行:

總結

使用Task去處理同步、異步上手挺容易的!
然比較需注意的點在如果你要在裡面用await,外層一定要加上async,否則會報錯。

程式碼放置庫:https://github.com/yuhsiang237/TaskAsync

參考資料

[Day3]C#中Task與Thread比較 - C# SyncAndAsync

前言

在上回 Post not found: 什麼是同步與異步-C-SyncAndAsync [Day2]什麼是同步與異步 - C# SyncAndAsync ,列出了同步異步差異,而今回就朝異步的Task、Thread邁進。

什麼是Task與Thread

在此將Task、Thread做一個表格比較:

Task Thread
描述 Task類別代表不會傳回值,而且通常會以非同步方式執行的單一作業。 Task物件是工作架構非同步模式的其中一個核心元件,第一次是在 .NET Framework 4 中引進。 由於物件所執行的工作 Task 通常會線上程集區執行緒上以非同步方式執行,而不是在主應用程式執行緒上同步執行,因此您可以使用 Status 屬性以及 IsCanceled 、 IsCompleted 和 IsFaulted 屬性來判斷工作的狀態。 最常見的情況是使用 lambda 運算式來指定工作要執行的工作。

針對傳回值的作業,您可以使用Task<TResult>類別。

可建立和控制執行緒,設定執行緒的優先權,並取得它的狀態。 Thread是C#中最早的多執行緒模型,後來才推出Task。
基於 基於Action,Func的更加現代的執行緒模型。支援模板引數。 基於delegate。僅受限於固定引數。
C#中常配套的關鍵詞 async、await Start、Suspend、Resume、Join、Abort、ThreadPool
namespace System.Threading.Tasks System.Threading
備註 Task的目的,就是要替代Thread,未來可能比較主流 -

總結

可以得知Task、Thread都是能夠處理異步的解決方案,而Task算是Thread的改良易用的封裝版本,因此接下來會先以Task為主進行深究,最後才是Thread。

而在MSDN官方也提供了一個非同步程式的配套設計模式:
https://docs.microsoft.com/zh-tw/dotnet/standard/asynchronous-programming-patterns/

參考資料

[Day2]什麼是同步與異步 - C# SyncAndAsync

前言

在上回 [Day1]為了某個夢想而開始 - C# SyncAndAsync ,列出了學習方向,而今回就朝學習目標邁進。

什麼是同步與異步

在此將同步、非同步做一個表格比較:

異步 同步
描述 又稱非同步(Asynchronous、async),調用在發出之後,這個調用就直接返回了,所以沒有返回結果。當一個異步過程調用發出後,調用者不會立刻得到結果。而是在調用發出後,被調用者通過狀態、通知或通過回調函數,讓調用者能響應結果。 又稱同步(Synchronous、sync),同步還可以理解為:發出一個調用時,在沒有得到結果之前,該調用就不返回。
使用場景 同時,一次做多件事情 同時,一次做一件事情
圖例
例子 非同步串行通信、AJAX -
C#中常見的關鍵詞 async、await、Task、Thread -

總結

在這篇中可以得知,如果想加快某些代碼執行的速度,而其彼此又不相干,就能將其以非同步方法實作。
且非同步方法調用後立即返回,因此不會有結果,而是用通知、回調方式去獲得結果。
而在C#中Thread與Task都能做到異步,下回則主要介紹Thread與Task的差異囉。

參考資料