비동기 API 사용해보기

서병수·2023년 7월 20일
0

쓰레드와 테스크

목록 보기
5/5

다음 두 함수는 동일한 내용을 동기버전과 비동기버전으로 구현한 코드이다.

  동기버전
        static long CopySync(string FromPath, string ToPath)
        {
            using(var fromStream = new FileStream(FromPath,FileMode.Open))
            {
                long totalCopied = 0;
                using(var toStream = new FileStream(ToPath,FileMode.Create))
                {
                    byte[] buffer = new byte[1024];
                    int nRead = 0;
                    while((nRead = fromStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        toStream.Write(buffer,0, nRead);    
                        totalCopied += nRead;
                    }
                }
                return totalCopied; 
            }           
        }
  비동기버전
        async Task<long> CopySync(string FromPath, string ToPath)
        {
            using (var fromStream = new FileStream(FromPath, FileMode.Open))
            {
                long totalCopied = 0;
                using (var toStream = new FileStream(ToPath, FileMode.Create))
                {
                    byte[] buffer = new byte[1024];
                    int nRead = 0;
                    while ((nRead = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                    {
                        await toStream.WriteAsync(buffer, 0, nRead);
                        totalCopied += nRead;
                    }
                }
                return totalCopied;
            }
        }
1.FileStream.Read 이 메서드의 형태는 다음과 같다.
public virtual int Read(byte[] buffer, int offset, int count);
-> buffer : 읽은 데이터를 저장할 배열
-> offset : 저장을 시작할 숫자 (EX: 0이면 0부터 저장함)
-> count : 읽을 최대 바이트 수 
-> 반환값 : 읽은 바이트 수

2.FileStream.Write 이 메서드의 형태는 다음과 같다.
public virtual void Write(byte[] buffer, int offset, int count);
-> buffer : 데이터를 저장한 배열
-> offset : 쓰기 시작할 숫자 (EX: 0이면 0부터 씀)
-> count : 쓸 바이트 수 

3.두 메서드는 파일을 복사하고, 복사를 마친 뒤에는 파일의 크기를 반환한다.

4.동기버전은 메서드가 호출되면 실행이 종료될 때까지 사용자 인터페이스가 응답을 못하지만
  비동기버전은 응답을 한다.
  
5. 위 두 메서드를 이용해서 실습을 해보았다. 소스코드는 아래와 같다.
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Asyncfile
{
   public partial class Form1 : Form
   {
       long CopySync(string FromPath, string ToPath)
       {
           SyncCopy.Enabled = false;
           long totalCopied = 0;
           using (var fromStream = new FileStream(FromPath, FileMode.Open))
           {
               
               using (var toStream = new FileStream(ToPath, FileMode.Create))
               {
                   byte[] buffer = new byte[1024];
                   int nRead = 0;
                   while ((nRead = fromStream.Read(buffer, 0, buffer.Length)) != 0)
                   {
                       toStream.Write(buffer, 0, nRead);
                       totalCopied += nRead;
                       pbCopy.Value = (int)(((double)totalCopied/(double)fromStream.Length)*pbCopy.Maximum);
                   }    
               }
               SyncCopy.Enabled = true;
               return totalCopied;
           }
       }
       async Task<long> CopyAsync(string FromPath, string ToPath)
       {
           AsyncCopy.Enabled = false;
           using (var fromStream = new FileStream(FromPath, FileMode.Open))
           {
               long totalCopied = 0;
               using (var toStream = new FileStream(ToPath, FileMode.Create))
               {
                   byte[] buffer = new byte[1024];
                   int nRead = 0;
                   while ((nRead = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                   {
                       await toStream.WriteAsync(buffer, 0, nRead);
                       totalCopied += nRead;
                       pbCopy.Value = (int)(((double)totalCopied / (double)fromStream.Length) * pbCopy.Maximum);
                   }
               }
               AsyncCopy.Enabled = true;
               return totalCopied;
           }
       }

       public Form1()
       {
           InitializeComponent();
       }

       private void btnFindSource_Click(object sender, EventArgs e)
       {
           OpenFileDialog dlg = new OpenFileDialog();
           if(dlg.ShowDialog() == DialogResult.OK )
           {
               txtSource.Text = dlg.FileName;
           }
       }

       private void btnFindTarget_Click(object sender, EventArgs e)
       {
          SaveFileDialog dlg = new SaveFileDialog();
           if (dlg.ShowDialog() == DialogResult.OK)
           {
               txtTarget.Text = dlg.FileName;
           }
       }

       private async void AsyncCopy_Click(object sender, EventArgs e)
       {
           long totalCopied = await CopyAsync(txtSource.Text,txtTarget.Text);
       }

       private void SyncCopy_Click(object sender, EventArgs e)
       {
           long totalCopied = CopySync(txtSource.Text, txtTarget.Text);
       }

       private void Cancel_Click(object sender, EventArgs e)
       {
           MessageBox.Show("UI 반응 테스트 성공");
       }

       private void button1_Click(object sender, EventArgs e)
       {
           pbCopy.Value = 0;
       }
   }
}

동기로 파일을 복사하면 Cancel이 반응을 잘 하지 못하고 비동기로 파일을 복사하면 Cancel이 잘 반응한다.

profile
안녕하십니까 인사올립니다

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

좋은 글 감사합니다!

답글 달기