Inno 3.6 Async programming Flashcards

(22 cards)

1
Q

What is the purpose of async/await in C#?

A

The async and await keywords are used to write asynchronous, non-blocking code in a readable way. **An async method returns a Task or Task<T>**, allowing it to be awaited.</T>

The await keyword pauses the method execution until the awaited task completes, freeing the calling thread in the meantime.

This helps keep the UI or server responsive. Avoid using async void unless writing event handlers — it doesn’t return a task, so exceptions can’t be caught.

Async methods compile to state machines under the hood to maintain execution flow across awaits.

ASYNC INITIALIZES STATE MACHINE

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is the role of the async state machine in .NET?

A

When an async method is compiled, it’s transformed into a state machine to manage asynchronous control flow. This machine uses a MoveNext() method to step through states triggered by await. Internally, it implements the IAsyncStateMachine interface and uses AsyncTaskMethodBuilder to build the final Task.

Each await creates a pause point and the state machine resumes from that point.

The compiler generates switch or if-else blocks to manage states. This makes asynchronous logic behave more like sequential code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

How can deadlocks be prevented in async code?

A

Deadlocks in async code often occur when using .Result or .Wait() on tasks, especially in UI or ASP.NET synchronization contexts.

To prevent this, always use await instead of blocking calls. Async method calls should be propagated — if one method is async, callers should also be async.

This avoids capturing the current synchronization context in a blocking way. Another common trick is using ConfigureAwait(false) in library code to skip context capturing. Proper async flows eliminate the risk of thread starvation and deadlocks.

dont use .Result or Wailt in async methods, use await instead

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is the role of the Task Scheduler in .NET?

A

The TaskScheduler handles queuing and running tasks on appropriate threads.

It abstracts away the low-level threading logic and manages task execution order and concurrency. In .NET Core and newer, the default scheduler works with the thread pool. Custom schedulers can control how and where tasks run. Methods like Task.Run and Task.Factory.StartNew rely on it. When combined with ConfigureAwait(false), it helps manage how continuations are scheduled.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is the SynchronizationContext used for?

A

SynchronizationContext captures the environment where a task runs — typically the UI or request thread — and ensures continuations run on the same context. It’s especially used in .NET Framework apps (WinForms, WPF, ASP.NET).

When await resumes, it posts the continuation back to the captured context unless ConfigureAwait(false) is used. This helps maintain thread affinity, such as updating UI controls from async methods. In .NET Core apps, there’s no synchronization context by default unless explicitly installed.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

How is async cancellation handled in C#?

A

Async operations can be cancelled using a CancellationTokenSource and CancellationToken. The token is passed into async methods that periodically check token.IsCancellationRequested. Calling .Cancel() on the source signals all linked tasks to stop. Proper cancellation involves checking the token and throwing OperationCanceledException to end the task gracefully. This is essential for responsive apps that may need to stop long-running or I/O-bound operations.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is Task Parallelism in .NET?

A

Task parallelism involves running multiple tasks concurrently, often using Task.Run() or Task.Factory.StartNew().

These methods execute code on thread pool threads and are ideal for CPU-bound work. Tasks can be chained using .ContinueWith() to perform follow-up logic after a task finishes.

Task.WhenAll waits for multiple tasks to finish, while Task.WhenAny completes when the first task finishes.

Be careful with .Wait() or .WaitAll() — they block the calling thread and may cause deadlocks in async contexts. Prefer await with WhenAll for modern asynchronous patterns.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What are the performance considerations of async methods?

A

Async methods add some overhead due to the generated state machine and task scheduling.

If an operation completes synchronously, creating the async machinery may be unnecessary. This is where ValueTask helps — it avoids allocations when returning completed results, unlike Task, which always allocates.

However, ValueTask is more complex and should be used only when performance profiling shows clear benefit. Avoid using async for methods that don’t perform I/O or await anything — it just adds cost without value.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What is TaskCompletionSource in .NET?

A

TaskCompletionSource<T> is a way to create a Task<T> manually and control when it completes. It’s often used when wrapping non-task-based asynchronous APIs or implementing custom async logic. You create the source, expose its Task, and call **SetResult(), .SetException(), or .SetCanceled()** when ready. It separates the producer (who completes the task) from the consumer (who awaits it). It’s a powerful but low-level tool and must be used carefully to avoid race conditions or unobserved exceptions.</T></T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is IAsyncEnumerable<T> and how are async streams used?</T>

A

IAsyncEnumerable<T> represents an asynchronous stream of data — you consume it using await foreach. Unlike regular IEnumerable, it allows fetching items asynchronously, useful for reading from files, databases, or web APIs where data arrives over time. You can yield results using yield return combined with await. It's ideal when processing large or delayed data sets without loading everything into memory. The pattern helps make your code reactive and scalable while keeping it readable.</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is AsyncLocal<T> and when should it be used?</T>

A

AsyncLocal<T> provides a way to store data that's local to the current async control flow, like a thread-local variable but for async code. It's used to preserve context, such as user info, correlation IDs, or logging scope, across await boundaries. The value flows through continuations even if they run on different threads. It’s useful in advanced scenarios like building frameworks or middleware. Be cautious — values can leak across contexts if not managed properly.</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is the difference between Value Types and Reference Types in .NET?

A

Value types (like int, bool, structs) hold their data directly on the stack or inline in memory. Reference types (like class, string, object) store a reference (pointer) to data located on the heap.

Value types are generally more performant for small, short-lived data because they avoid heap allocation.

However, they are copied on assignment or when passed to methods, which can lead to unintended behavior. Reference types are shared across references, making them suitable for complex or mutable data structures.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What is async void, and why is it discouraged?

A

async void defines an asynchronous method that doesn’t return a Task, which makes it unawaitable and untrackable.

This is dangerous because exceptions thrown inside the method can’t be caught with a try-catch from the caller. It’s mainly used for event handlers, where returning a Task isn’t possible. In other contexts, you should always return Task or Task<T> for proper exception handling and awaitability. Avoid using async void in library or business logic code.</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Can a Task return void in C#?

A

No — a Task itself is a representation of an asynchronous operation, and its return type is void-like in structure.

But in method signatures, Task and Task<T> are used instead of void. If a method returns void, you lose the ability to await it or catch exceptions. Use Task for asynchronous methods that return no value and</T>

Task<T> for those that return a result. Using void in async methods should be limited to event handlers only</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What does the compiler generate when you write an async method?

A

When you define an async method, the C# compiler transforms it into a state machine that implements IAsyncStateMachine.

This structure uses a MoveNext() method to track progress through await points.

It also includes a TaskBuilder (AsyncTaskMethodBuilder) that constructs and manages the Task returned to the caller.

Each await is translated into a state transition, and continuations are scheduled using the current synchronization context or task scheduler. This transformation ensures non-blocking, resumable execution.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What happens when you await a completed Task?

A

When you await a completed task, the continuation runs synchronously, unless you’re using ConfigureAwait(false). This means the await doesn’t introduce a real async suspension — the compiler sees that the task is already finished and continues immediately. This is an optimization that avoids unnecessary state machine complexity and thread scheduling. You can use it to avoid performance overhead in hot paths where results are often cached. Be careful though — side effects or blocking operations might still occur within that continuation.

17
Q

How do exceptions work in async methods?

A

Exceptions thrown in async methods are captured and stored inside the returned Task.

When the Task is awaited, the exception is re-thrown at the await point.

This means you should wrap await in try-catch blocks to handle errors. If you don’t await the task, exceptions may go unobserved and cause problems like application crashes. For fire-and-forget tasks, always attach a continuation or use logging to track failures.

18
Q

How can you wrap an old-style callback API with async/await?

A

You can wrap older APM (Begin/End) or EAP (Event-based) APIs using TaskCompletionSource<T>. You manually complete the task when the callback/event fires using .SetResult() or .SetException(). This gives you a clean, modern async API around legacy code. For example, in file I/O or socket APIs, this technique is often used in interop or migration scenarios. It provides better composability and error handling with async/await.</T>

19
Q

What happens if you forget to await a Task?

A

If you forget to await a Task, it will still run, but you won’t be able to catch exceptions or know when it completes. This can lead to unobserved exceptions, race conditions, or wasted resources. Tools like analyzers and code linters can warn you about such mistakes. In critical logic, always await tasks unless you’re intentionally fire-and-forgetting with logging or tracking.

EXCEPTIONS, RACE CONDITION

20
Q

How do you safely fire-and-forget an async method?

A

To safely fire-and-forget, you should use a try-catch inside the method and log exceptions. Optionally, you can use a helper like Task.Run(() => SomeAsyncMethod().LogExceptions()) or keep track of the task in a list for shutdown synchronization. In production services, unmonitored tasks can be a major source of bugs or crashes. Always ensure fire-and-forget tasks are defensive and monitored.

21
Q

What is the role of ConfigureAwait(false)?

A

ConfigureAwait(false) tells the awaiter not to capture the current SynchronizationContext. This is especially useful in libraries and ASP.NET Core, where continuing on the original context is unnecessary. It avoids deadlocks and improves performance by allowing continuations to run on the thread pool. In UI apps (like WPF or WinForms), you may need to omit it to continue on the UI thread. Always use it in library code unless thread affinity is required.

22
Q

Can async methods be used in constructors or property getters/setters?

A

No — C# doesn’t allow async constructors or property getters/setters. Constructors can’t be awaited, and async properties would require returning Task, which breaks the expectations of property access. Instead, use a factory method like public static async Task<MyClass> CreateAsync(). For properties, consider exposing an async method (e.g., LoadAsync) that sets internal fields.</MyClass>