비동기 프로그래밍
C#에서는 async과 await 키워드를 사용하여 비동기 프로그래밍을 구현
await 작업이 이루어지는 경우 await 이후의 작업은 쓰레드 풀의 유휴 쓰레드를 할당받아 수행하게됨
async
해당 메서드 내에 await 키워드를 사용할 수 있게 만들어줌
즉, await를 가지고 있을 수 있음을 알려주는 역할
- 반드시 void / Task / Task<T> 중 하나를 반환해야함
- Task : 백그라운드 속성의 쓰레드, 쓰레드 풀 사용
System.Threading.Tasks 네임스페이스가 필요함
- Task : 백그라운드 속성의 쓰레드, 쓰레드 풀 사용
- void를 사용시 비동기 메서드를 호출하는 쪽에서 비동기를 제어할 수 없음
await
비동기 작업의 흐름을 제어하는 키워드
단항 연산자로 쓰이며, awaitable 형식(Task 또는 Task<T>를 반환하는 함수 또는 메서드)의 인수를 가짐
- 피연산자의 비동기 작업이 완료될 때까지 바깥쪽 async 메서드의 실행을 일시 중단시킴
- 비동기 작업의 리턴값이 있다면 작업 결과를 리턴
- 이미 완료된 비동기 작업 피연산자에 적용시 async 메서드를 중단시키지 않고 결과 즉시 반환
- 비동기 메서드를 실행하는 쓰레드를 블로킹하지 않음
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
public static async void TaskA() // 작업 A
{
string syncString = "비동기임에도 동기 처럼 사용되는 것을 보여 주기 위한 변수";
int n = await Task.Run(() =>
{
Console.WriteLine($"Do TaskA, returns 10 (ThreadID:{Thread.CurrentThread.ManagedThreadId})");
Thread.Sleep(2000); // 작업이 오래 걸리고 있는 중
return 10;
});
Console.WriteLine($"Do TaskB with {n} from TaskA (ThreadID:{ Thread.CurrentThread.ManagedThreadId})");
Console.WriteLine(syncString);
}
public static void Main()
{
TaskA();
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Main thread waits UI event..{i + 1} (ThreadID:{ Thread.CurrentThread.ManagedThreadId})");
Thread.Sleep(1000);
}
Console.WriteLine("Program finished");
}
}
위 코드를 실행할 경우, 비동기로 작업하는 TaskA 내부에서 await가 걸려있는 Task에서 작업 흐름이 제어됨
따라서 실행 결과는 다음과 같음
Do TaskA, returns 10 (ThreadID:4) // 비동기 작업 시작
Main thread waits UI event..1 (ThreadID:1)
Main thread waits UI event..2 (ThreadID:1)
Main thread waits UI event..3 (ThreadID:1)
Do TaskB with 10 from TaskA (ThreadID:4) // 비동기 작업 완료, 다음 작업 시작
비동기임에도 동기 처럼 사용되는 것을 보여 주기 위한 변수
Main thread waits UI event..4 (ThreadID:1)
Main thread waits UI event..5 (ThreadID:1)
Program finished
Attribute
프로그램의 코드에 메타데이터를 추가하는 방법으로 사용 목적은 다음과 같음
- 메타데이터 제공 - [Serializable], [Obsolete] 등
- 컴파일 타임 검사 - [Conditional] 등
- 런타임 동작 변경 - [Authorize] 등
- 코드 생성 - [DataContract], [DataMember] 등
클래스, 메서드, 필드, 이벤트, 프로퍼티 등의 요소에 적용할 수 있으며 아래와 같은 형태로 사용됨
[AttributeUsage(AttributeTargets.SomeElement)]
public class MyAttribute : Attribute
{
// 속성, 메서드, 이벤트 등을 정의
}
Conditional Attribute
컴파일러에게 조건부 컴파일을 지시하는데 사용
- System.Diagnostics 네임스페이스가 필요
- [Conditional("CONDITION_SYMBOL")] 형태로 사용
- 클래스나 구조체 안에 있는 void형 메서드에서만 사용할 수 있음
아래 예시에서 Conditional Attribute에 의해 DEBUG 심볼이 정의되어있을 때만 MyMethod()가 컴파일됨
using System;
using System.Diagnostics;
class Program
{
[Conditional("DEBUG")]
static void MyMethod()
{
Console.WriteLine("Debug mode");
}
static void Main()
{
MyMethod();
}
}
Obsolete Attribute
특정 코드가 더이상 사용되지 않는다는 경고를 표시
- System 네임스페이스가 필요
- [Obsolete(string message, bool error)] 형태로 사용
- 두번째 매개변수인 error가 true일시 컴파일시 오류를 발생시켜 컴파일을 막음
- 각 매개변수는 생략 가능
[Obsolete("This method is obsolete. Use a different method instead.", true)]
public void MyObsoleteMethod()
{
// ...
}
Dll Import Attribute
외부의 DLL(동적 링크 라이브러리)을 코드에서 사용하기 위해 임포트하는데 사용
- [DllImport("라이브러리 이름")] 형태로 사용
[DllImport("라이브러리 이름")]
public static extern 리턴타입 메서드이름(매개변수);
ApiController Attribute
컨트롤러 클래스에 부여되며, 해당 클래스가 웹 API 컨트롤러임을 나타냄
- [ApiController] 형태로 사용
- 사용하기 위해서는 Route Attribute가 필요
- ApiController Attribute가 부여된 클래스는 다음과 같은 기능들을 제공함
- 입력 모델 바인딩 : 요청의 body에 있는 데이터를 모델로 바인딩하는 기능을 자동으로 제공
- 유효성 검사 : 데이터 모델에 대한 유효성 검사를 자동으로 수행
- 예외 처리 : 예외 처리를 자동으로 수행
- 라우팅 및 URL 생성 : 웹 API의 엔드포인트를 라우팅하고 URL을 생성하는데 필요한 기능들 제공
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
// GET api/users
[HttpGet]
public IActionResult Get()
{
// 사용자 목록을 조회하는 로직
return Ok(users);
}
// POST api/users
[HttpPost]
public IActionResult Post([FromBody] User user)
{
// 새로운 사용자를 생성하는 로직
CreateUser(user);
return CreatedAtAction(nameof(Get), new { id = user.Id }, user);
}
// PUT api/users/{id}
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody] User user)
{
// 사용자 정보를 업데이트하는 로직
UpdateUser(id, user);
return NoContent();
}
// DELETE api/users/{id}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
// 사용자를 삭제하는 로직
DeleteUser(id);
return NoContent();
}
}
Route Attribute
컨트롤러 액션 메서드나 컨트롤러 클래스에 적용, 해당 액션 메서드나 컨트롤러의 라우팅 경로를 지정
웹 API 엔드포인트의 경로를 정의하고 클라이언트의 요청을 해당 경로와 일치하는 컨트롤러 액션 메서드로 라우팅
- [Route("api/[controller]")] 형태로 사용하여 경로를 지정해 원하는 URL 패턴을 생성
- [Route("api/[controller]/{id}")] 형태로 사용하여 경로 변수를 정의
- [Route("api/[controller]/{id?}")] 형태로 사용하여 선택적 경로 변수를 정의, 해당 변수가 없어도 라우팅 가능
- [Route("api/[controller]/{id:int}")] 형태로 사용하여 정규식 패턴을 지정
[Route("api/[controller]/{id}")]
public IActionResult GetById(int id)
{
// id를 사용하여 특정 아이템을 가져오는 로직
// ...
}
Frombody Attribute
웹 API에서 HTTP 요청의 body에 있는 데이터를 모델로 바인딩하기 위해 사용
- [FromBody] 형태로 사용
- JSON 형식 데이터를 C# 클래스로 변환하는 등의 기능으로 사용할 수 있음
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
[HttpPost]
public IActionResult CreateUser([FromBody] User user)
{
// 요청의 본문에 있는 데이터를 User 클래스로 바인딩하여 사용하는 로직
if (ModelState.IsValid)
{
// 유효성 검사를 통과한 경우, User 객체를 사용하여 새로운 사용자 생성
// ...
return Ok();
}
else
{
// 유효성 검사에 실패한 경우, BadRequest를 반환하거나 오류 처리
// ...
return BadRequest();
}
}
HttpXxx Attribute
웹 API에서 HTTP 요청 메서드를 지정하는데 사용
- [HttpGet], [HttpPost], [HttpPut], [HttpDelete] 형태로 사용
- 웹 API의 액션 메서드에 대한 라우팅 및 요청 처리 방식을 지정
[HttpGet]
public IActionResult Get()
{
// HTTP GET 요청을 처리하는 로직
// ...
}
[HttpPost]
public IActionResult Post([FromBody] MyModel model)
{
// HTTP POST 요청을 처리하는 로직
// ...
}
Require Attribute
컴파일 타임에 코드의 유효성을 검사하고 필요한 요구사항을 지정하는데 사용
- [Require] 형태로 사용
- 반드시 데이터가 입력되어야함(NULL이 허용되지 않음)
- 메서드나 클래스의 입력 인자에 대한 유효성 검사 특성을 요구할 수 있음
- 내장된 속성이 아닌 사용자가 직접 정의해야하는 커스텀 속성이기때문에 주의가 필요
using System.ComponentModel.DataAnnotations;
public class UserRegistrationModel
{
[Required(ErrorMessage = "이름을 입력해주세요.")]
public string Name { get; set; }
[Required(ErrorMessage = "비밀번호를 입력해주세요.")]
[MinLength(6, ErrorMessage = "비밀번호는 최소 6자 이상이어야 합니다.")]
public string Password { get; set; }
}
'개인공부 > Web API 게임 서버 공부' 카테고리의 다른 글
배경지식 - Redis (0) | 2023.04.20 |
---|---|
배경지식 - ORM (1) | 2023.04.20 |
배경지식 - ASP.NET (0) | 2023.04.19 |
배경지식 - API (0) | 2023.04.19 |
배경지식 - HTTP (1) | 2023.04.19 |
댓글