[C# 문법] C# async, await 이용하여 비동기 예제 프로그램 만들기

안녕하세요.

 

오늘은 C# 문법에서 async, await 키워드를 이용하여 비동기 예제 프로그램을 만들어 보려고 합니다.

 

동기와 비동기에 대해서 아주 간단하게? 차이점을 말씀을 드리면,

동기는 한마디로 동시에 행동이 일어 난다는건데요. 쉽게 말해 요청과 결과가 한 자리에서 바로 일어나는 걸 동기라고 이해하시면 되겠습니다.

 

반대로 비동기는, 동시에 일어나지 않고, 요청과 결과가 따로 일어날 수 있는 경우를 뜻하는데요.

 

오늘은 C#에서 비동기가 일어나도록 프로그램을 아주 간단하게? 만들어 보려고 합니다.

 

바로, async, await 2개의 키워드를 사용하여 비동기 프로그램을 만들 수 있는데요.

 

먼저 아래와 같이 WPF에서 UI를 구성해 주시기 바랍니다.

 

[UI 구성 모습]

UI 구성 모습

 

UI xaml 소스
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
<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="400">
    <Border Padding="10">
        <StackPanel>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
 
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
 
                <TextBlock Grid.Column="0" Grid.Row="0" Text="비동기 프로그램 예제" FontWeight="Bold" Margin="0 10 0 0"/>
                <Button x:Name="uiBtn_Async" Click="uiBtn_Async_Click" Grid.Column="1" Grid.Row="0" Margin="10 10 10 10" Content="Start" />
 
                <TextBlock Grid.Column="0" Grid.Row="1" Text="결과물 출력" />
                <RichTextBox x:Name="uiRtb_Output" Height="500" Grid.ColumnSpan="2" Grid.Row="2" IsReadOnly="True" AcceptsReturn="True"
                     HorizontalAlignment="Stretch"
                     VerticalAlignment="Stretch"/>
            </Grid>
 
        </StackPanel>
 
    </Border>
</Window>
 
cs

 

UI 소스코드는 위와 같습니다.

 

이제 Start 버튼을 클릭하면, 서로 다른 일을 하는 2개의 비동기 메서드를 만들어서 결과물이 출력되도록 하도록 하겠습니다.

 

예제 코드
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
 
namespace WpfTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        FlowDocument flowDoc = new FlowDocument();
 
        public MainWindow()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// 비동기 시작 버튼 클릭 이벤트
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiBtn_Async_Click(object sender, RoutedEventArgs e)
        {
            Start();
        }
 
        private async Task Start()
        {
            Task task1 = FirstAsync();
            Task task2 = SecondAsync();
 
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
            {
                flowDoc.Blocks.Add(new Paragraph(new Run($"비동기 시작")));
                uiRtb_Output.Document = flowDoc;
            }));
 
            await task1;
            await task2;
 
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
            {
                flowDoc.Blocks.Add(new Paragraph(new Run($"비동기 종료")));
                uiRtb_Output.Document = flowDoc;
            }));
        }
 
        /// <summary>
        /// 첫 번째, 비동기 메서드 선언
        /// </summary>
        /// <returns></returns>
        private async Task FirstAsync()
        {
            await Task.Run( () =>
            {
                for(int idx = 0; idx < 5; idx++)
                {
                    Thread.Sleep(500);
 
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
                    {
                        flowDoc.Blocks.Add(new Paragraph(new Run($"FirstAsync")));
                        uiRtb_Output.Document = flowDoc;
                    }));
                }
            });
        }
 
        /// <summary>
        /// 두 번째, 비동기 메서드 선언
        /// </summary>
        /// <returns></returns>
        private async Task SecondAsync()
        {
            await Task.Run( () =>
            {
                for(int idx = 0; idx < 5; idx++)
                {
                    Thread.Sleep(500);
 
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
                    {
                        flowDoc.Blocks.Add(new Paragraph(new Run($"SecondAsync")));
                        uiRtb_Output.Document = flowDoc;
                    }));
                }
            });
        }
    }
}
 
cs

 

실행 결과

 

위와 같이 비동기시작문구가 출력이 되고, 그 다음에 비동기 메서드 1, 2 번째 메서드가 각각 5번씩 출력이 되면서 비동기 메서드가 모두 끝나서야 마지막으로 비동기종료문구가 출력되는 것을 확인하실 수 있습니다.

 

이렇게 비동기 메서드가 끝나야 출력되는 이유는 await 키워드 때문인데요.

 

예제 코드
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
 
namespace WpfTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        FlowDocument flowDoc = new FlowDocument();
 
        public MainWindow()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// 비동기 시작 버튼 클릭 이벤트
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiBtn_Async_Click(object sender, RoutedEventArgs e)
        {
            Start();
        }
 
        private async Task Start()
        {
            Task task1 = FirstAsync();
            Task task2 = SecondAsync();
 
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
            {
                flowDoc.Blocks.Add(new Paragraph(new Run($"비동기 시작")));
                uiRtb_Output.Document = flowDoc;
            }));
 
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
            {
                flowDoc.Blocks.Add(new Paragraph(new Run($"비동기 종료")));
                uiRtb_Output.Document = flowDoc;
            }));
        }
 
        /// <summary>
        /// 첫 번째, 비동기 메서드 선언
        /// </summary>
        /// <returns></returns>
        private async Task FirstAsync()
        {
            await Task.Run( () =>
            {
                for(int idx = 0; idx < 5; idx++)
                {
                    Thread.Sleep(500);
 
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
                    {
                        flowDoc.Blocks.Add(new Paragraph(new Run($"FirstAsync")));
                        uiRtb_Output.Document = flowDoc;
                    }));
                }
            });
        }
 
        /// <summary>
        /// 두 번째, 비동기 메서드 선언
        /// </summary>
        /// <returns></returns>
        private async Task SecondAsync()
        {
            await Task.Run( () =>
            {
                for(int idx = 0; idx < 5; idx++)
                {
                    Thread.Sleep(500);
 
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate
                    {
                        flowDoc.Blocks.Add(new Paragraph(new Run($"SecondAsync")));
                        uiRtb_Output.Document = flowDoc;
                    }));
                }
            });
        }
    }
}
 
cs

 

실행 결과

 

 

만약 위와 같이 소스코드에서 await 키워드를 안쓰게 되면, “비동기시작”, “비동기종료가 찍히면서 동시에 비동기 메서드 1,2가 각각 수행되면서 출력되는 것을 확인하실 수 있습니다.

 

 

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY