비동기 프로그래밍

비동기 작업은 데이터베이스에서 쿼리가 실행되는 동안 스레드를 차단하지 않습니다. 비동기 작업은 풍부한 클라이언트 애플리케이션에서 반응형 UI를 유지하는 데 중요하며, 스레드를 확보하여 웹 애플리케이션의 다른 요청을 처리할 수 있는 웹 애플리케이션의 처리량을 늘릴 수도 있습니다.

.NET 표준에 따라 EF Core는 I/O를 수행하는 모든 동기 메서드에 비동기 대응 메서드를 제공합니다. 동기화 메서드와 동일한 효과를 가지며 C# asyncawait 키워드와 함께 사용할 수 있습니다. 예를 들어 데이터베이스 I/O가 수행되는 동안 스레드를 차단하는 DbContext.SaveChanges를 사용하는 대신 DbContext.SaveChangesAsync를 사용할 수 있습니다.

var blog = new Blog { Url = "http://sample.com" };
context.Blogs.Add(blog);
await context.SaveChangesAsync();

자세한 내용은 일반 C# 비동기 프로그래밍 문서를 참조하세요.

Warning

EF Core는 동일한 컨텍스트 인스턴스에서 실행되는 여러 병렬 작업을 지원하지 않습니다. 항상 작업이 완료될 때까지 대기한 후 다음 작업을 시작해야 합니다. 일반적으로 이 작업은 각 비동기 작업에서 await 키워드를 사용하여 수행합니다.

Warning

Microsoft.Data.SqlClient의 비동기 구현에는 알려진 이슈(예:#593, #601등)가 있습니다. 예기치 않은 성능 문제가 발생하는 경우 특히 큰 텍스트 또는 이진 값을 처리할 때 동기화 명령 실행을 대신 사용해 보세요.

참고 항목

EF Core는 사용 중인 기본 데이터베이스 공급자(예: Microsoft.Data.SqlClient)에 취소 토큰을 전달합니다. 이러한 토큰은 적용되거나 적용되지 않을 수 있습니다. 데이터베이스 공급자의 설명서를 참조하세요.

비동기 LINQ 연산자

LINQ 쿼리 실행을 비동기적으로 지원하기 위해 EF Core는 쿼리를 실행하고 결과를 반환하는 비동기 확장 메서드 집합을 제공합니다. 표준 동기 LINQ 연산자의 이러한 대응 항목에는 ToListAsync, SingleAsync, AsAsyncEnumerable 등이 포함됩니다.

var blogs = await context.Blogs.Where(b => b.Rating > 3).ToListAsync();

이는 LINQ 식 트리만 작성하고 데이터베이스에서 쿼리가 실행되도록 하지 않기 때문에 Where, OrderBy 등 LINQ 연산자의 비동기 버전이 없습니다. 쿼리 실행을 일으키는 연산자만 비동기 대응 항목이 있습니다.

Important

EF Core 비동기 확장 메서드는 Microsoft.EntityFrameworkCore 네임스페이스에 정의됩니다. 메서드를 사용하려면 이 네임스페이스를 가져와야 합니다.

클라이언트 쪽 비동기 LINQ 연산자

위에서 설명한 비동기 LINQ 연산자는 EF 쿼리에서만 사용할 수 있습니다. 클라이언트 쪽 LINQ to Objects 쿼리에는 사용할 수 없습니다. EF 외부에서 클라이언트 쪽 비동기 LINQ 작업을 수행하려면 System.Linq.Async 패키지를 사용합니다. 이 패키지는 서버에서 평가를 위해 변환할 수 없는 클라이언트에서 작업을 수행하는 데 특히 유용할 수 있습니다.

EF Core 6.0 이하에서는 System.Linq.Async를 참조하면 EF의 DbSets에 적용된 LINQ 연산자에서 모호한 호출 컴파일 오류가 발생합니다. 따라서 동일한 프로젝트에서 EF와 System.Linq.Async 모두 사용하기가 어렵습니다. 이 문제를 해결하려면 DbSet에 AsQueryable을 추가합니다.

var groupedHighlyRatedBlogs = await context.Blogs
    .AsQueryable()
    .Where(b => b.Rating > 3) // server-evaluated
    .AsAsyncEnumerable()
    .GroupBy(b => b.Rating) // client-evaluated
    .ToListAsync();