When AllowSynchronousContinuations option should be used with Channels?
Asked Answered
E

2

7

I'm implementing simple background job queue in Asp Net Core app. I've created BackgroundJobQueue which uses BoundedChannel<T> under the hood to enqueue items that will be processed via HostedService. Reading documentation I've stumbled upon ChannelOptions.AllowSynchronousContinuations settings for channel.

The descriptions according to msdn says:

Setting this option to true can provide measurable throughput improvements by avoiding scheduling additional work items. However, it may come at the cost of reduced parallelism, as for example a producer may then be the one to execute work associated with a consumer, and if not done thoughtfully, this can lead to unexpected interactions. The default is false.

I don't quite understand wether setting this option to true in my case is a good choice or not. Can someone explain + provide examples when this option is usefull/useless/harmfull?

Edit

Explanation I got:

According to the official statement, when producer depends on consumer, it waits for consumer's job to be done then starts its work, if you Enable the option, producer experiences more idle time. However, if you Disabled the option, because of parallelism, producer experiences lower idle time.

Isn't enabling option is bad? Since api request will take longer to process because producer will stay idle for a longer time. To clearify what I mean. Let's say I want to enqueue background job in my controller

public async Task<IActionResult> Action()
{
    // some code
   await _backgroundJobQueue(() => ....);
   return Ok();
}

If option is enabled, then producer experiences more idle time so It will take action longer to execute?

Elonore answered 1/8, 2021 at 16:55 Comment(3)
if you could, please provide experiment results for confirmation. you can set timer when all jobs done.Paxwax
I suggest not using it unless performance analysis indicates it would be useful. "unexpected interactions" can include deadlocks.Bibliographer
@StephenCleary A good pointElonore
P
1

You have a Background Queue. Therefore, You are synchronizing operations by using Queuing Jobs. it is better to Enable it because you don not want parallelism and the document claims that "it provides measurable throughput improvements"

as for example a producer may then be the one to execute work associated with a consumer

According to the official statement, when producer depends on consumer, it waits for consumer's job to be done then starts its work, if you Enable the option, producer experiences more idle time. However, if you Disabled the option, because of parallelism, producer experiences lower idle time.

This is what i understood and exemplified

Paxwax answered 1/8, 2021 at 17:52 Comment(5)
@Elonore IF producer depends on consumer otherwise it doesn't suffer.Paxwax
So will it work as fire and forget then? As far as I understand producer doesn't depend on consumerElonore
@Elonore base on your logic, Yes it's better to enable it, because parallelism doesn't much more effective here.Paxwax
This is quite not a scope of a question but what about situation when bounded channel is full? Code will asyncronously wait until there will be enough space to enqueue job? So theoretically if my channel is full my api won't be able to process requests?Elonore
@Elonore theoretically, if you encounter such traffic, you crash sooner when parallelism is enabled because it's much more expensive.Paxwax
P
2

If queue is not empty - all operations are Asynchronous.

If queue is empty AllowSynchronousContinuations comes into play

Below are very simple approximation samples:

AllowSynchronousContinuations is TRUE

void Producer()
{
    T instance = new T(); 
    
    Consumer(instance);

    // 'instance' object passed directly to the consumer and the producer will get execution control once the consumer completes processing.
}

AllowSynchronousContinuations is FALSE

void Producer()
{
    T instance = new T(); 
    
    Task.Run(() => Consumer(instance));

    // instance stored in queue and work scheduled for execution. The producer will get execution control immediately after scheduling
}
Pavlov answered 12/4, 2023 at 16:58 Comment(1)
Please, add more concrete System.Threading.Channels.Channel-related details, if you can. What is Consumer method here? And where is the channel-object?Olag
P
1

You have a Background Queue. Therefore, You are synchronizing operations by using Queuing Jobs. it is better to Enable it because you don not want parallelism and the document claims that "it provides measurable throughput improvements"

as for example a producer may then be the one to execute work associated with a consumer

According to the official statement, when producer depends on consumer, it waits for consumer's job to be done then starts its work, if you Enable the option, producer experiences more idle time. However, if you Disabled the option, because of parallelism, producer experiences lower idle time.

This is what i understood and exemplified

Paxwax answered 1/8, 2021 at 17:52 Comment(5)
@Elonore IF producer depends on consumer otherwise it doesn't suffer.Paxwax
So will it work as fire and forget then? As far as I understand producer doesn't depend on consumerElonore
@Elonore base on your logic, Yes it's better to enable it, because parallelism doesn't much more effective here.Paxwax
This is quite not a scope of a question but what about situation when bounded channel is full? Code will asyncronously wait until there will be enough space to enqueue job? So theoretically if my channel is full my api won't be able to process requests?Elonore
@Elonore theoretically, if you encounter such traffic, you crash sooner when parallelism is enabled because it's much more expensive.Paxwax

© 2022 - 2024 — McMap. All rights reserved.