Rx code blocks UI thread? - c#

I'm experiencing Reactive Programming (Rx) and one of its interesting feature is subscribing and observing on different threads. But here somehow it blocks the UI thread. Technically I don't have any method returning Task (async method), so here I'm trying to mimic a long process with Thread.Sleep:
IEnumerable<Item> _search(string searchText)
{
Thread.Sleep(3000);
//return result by querying ...
//...
return someResult;
}
I have a ViewModel class like this:
public class ViewModel {
public ViewModel(){
//this SubscribeOn may not be necessary but I just try it here for sure
SearchTextStream.SubscribeOn(NewThreadScheduler.Default)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(searchText => {
var items = _search(searchText);
}, ex => {
//handle error
});
}
public string SearchText
{
get
{
return _searchText.FirstAsync().Wait();
}
set
{
_searchText.OnNext(value);
}
}
ISubject<string> _searchText = new BehaviorSubject<string>("");
public IObservable<string> SearchTextStream
{
get
{
return _searchText.AsObservable().DistinctUntilChanged();
}
}
}
Actually without using Thread.Sleep, I can still see it blocks the UI but not very obvious, so I just use it to make it more obvious. As I said, the scenario here is that I have just a normal method without any task or async. It may be a long-running method. Using with RX, I don't know which should be done to make it behave like async (as when using a Task.Run)?
I'm testing on a WPF application if it matters.

You're calling _search(searchText) on the DispatcherScheduler.Current scheduler - and hence, with the Thread.Sleep you're blocking the UI.
You really should make _search return an observable.
IObservable<IEnumerable<Item>> _search(string searchText)
{
Thread.Sleep(3000);
//return result by querying ...
//...
return Observable.Return(new [] { new Item() });
}
Now the constructor should look like this:
public ViewModel()
{
SearchTextStream
.ObserveOn(System.Reactive.Concurrency.Scheduler.Default)
.SelectMany(searchText => _search(searchText))
.ObserveOnDispatcher()
.Subscribe(items =>
{
/* do something with `items` */
}, ex =>
{
//handle error
});
}

Related

C# Reusable or Persistent Tasks that behave like Threads

With threads, you can create persistent, reusable local variables which are useful for things like client connections. However, with Tasks like ActionBlock from System.Threading.Tasks.Dataflow, there does not appear to be any sort of persistence or reusability of the action block. So for an ActionBlock that involves interacting with a client, my understanding is that you either need to initialize a client connection from scratch or reuse one in a higher scope (with locking?).
The use case: I am using a .NET library that inverts control. The bulk of the logic (aside from startup and shutdown) must be in a single Task method named ProcessEventsAsync, called by the library, that receives an IEnumerable of data. ProcessEventsAsync must do some processing of all the data, then send it out to some downstream consumers. To improve performance, I am trying to parallelize the logic within ProcessEventsAsync using Tasks. I also want to gather some performance metrics from this Task.
Let me give a detailed example of what I'm doing:
internal class MyClass
{
private String firstDownStreamConnectionString;
private String secondDownStreamConnectionString;
private SomeClient firstClient;
private SomeClient secondClient;
private ReportingClient reportingClient;
private int totalUnhandledDataCount;
public MyClass(String firstDownStreamConnectionString, String secondDownStreamConnectionString, String reportingClientKey)
{
this.firstDownStreamConnectionString = firstDownStreamConnectionString;
this.secondDownStreamConnectionString = secondDownStreamConnectionString;
this.DegreeOfParallelism = Math.Max(Environment.ProcessorCount - 1, 1);
this.reportingClient = new ReportingClient (reportingClientKey, DegreeOfParallelism);
this.totalUnhandledDataCount = 0;
}
// called once when the framework signals that processing is about to be ready
public override async Task OpenAsync(CancellationToken cancellationToken, PartitionContext context)
{
this.firstClient = SomeClient.CreateFromConnectionString(this.firstDownStreamConnectionString);
this.secondClient = SomeClient.CreateFromConnectionString(this.secondDownStreamConnectionString );
await Task.Yield();
}
// this is called repeatedly by the framework
// outside of startup and shutdown, it is the only entrypoint to my logic
public override async Task ProcessEventsAsync(CancellationToken cancellationToken, PartitionContext context, IEnumerable<Data> inputData)
{
ActionBlock<List<Data>> processorActionBlock = new ActionBlock<List<Data>>(
inputData =>
{
SomeData firstDataset = new SomeData();
SomeData secondDataset = new SomeData();
int unhandledDataCount = 0;
foreach (Data data in inputData)
{
// if data fits one set of criteria, put it in firstDataSet
// if data fits other set of criteria, put it in secondDataSet
// otherwise increment unhandledDataCount
}
Interlocked.Add(ref this.totalUnhandledDataCount, unhandledDataCount);
lock (this.firstClient)
{
try
{
firstDataset.SendData(this.firstClient);
} catch (Exception e)
{
lock(this.reportingClient)
{
this.reportingClient.LogTrace(e);
}
}
}
lock (this.secondClient)
{
try
{
secondDataset.SendData(this.secondClient);
} catch (Exception e)
{
lock(this.reportingClient)
{
this.reportingClient.LogTrace(e);
}
}
}
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = this.DegreeOfParallelism
});
// construct as many List<Data> from inputData as there is DegreeOfParallelism
// put that in a variable called batches
for(int i = 0; i < DegreeOfParallelism; i++)
{
processorActionBlock.Post(batches[i]);
}
processorActionBlock.Complete();
processorActionBlock.Completion.Wait();
await context.CheckpointAsync();
}
}
I tried to keep this to only the relevant code, I omitted the processing logic, most metric gathering, how data is sent out, shutdown logic, etc.
I want to utilize some flavor of Task that allows for reusability. I don't want to reuse a single client connection for all running Tasks of this type, nor do I want each Task to create a new client connection each time it is invoked. I do want each Thread-like Task to have a persistent set of client connections. Ideally, I also do not want to create a new class that wraps a Task or which extends an abstract class/interface in System.Threading.Tasks.Dataflow.
It sounds like you just need a class that stores the dependencies?
void Main()
{
var doer1 = new ThingDoer();
var doer2 = new ThingDoer();
// A & B use one pair of clients, and C & D use another pair
var taskA = doer1.DoTheThing();
var taskB = doer1.DoTheThing();
var taskC = doer2.DoTheThing();
var taskD = doer2.DoTheThing();
}
public class ThingDoer
{
private SomeClient _someClient;
private SomeErrorReportingClient _someErrorReportingClient;
public ThingDoer(SomeClient someClient, SomeErrorReportingClient someErrorReportingClient)
{
_someClient = someClient;
_someErrorReportingClient = someErrorReportingClient;
}
public ThingDoer()
: this(new SomeClient, new SomeErrorReportingClient)
{
}
public async Task DoTheThing()
{
// Implementation here
}
}
The concept of "reusability" isn't really compatible with tasks.
What you're describing sounds like an async delegate, or Func.
For example:
Func<Task> TestFunc = async () =>
{
Console.WriteLine("Begin");
await Task.Delay(100);
Console.WriteLine("Delay");
await Task.Delay(100);
Console.WriteLine("End");
};
If the function is in scope, you'd just have to:
await TestFunc();
You can reuse it as many times as you need. You can also change the function to accept parameters.
Edit
You can also try AsyncLocal<T>. Per the documentation:
Because the task-based asynchronous programming model tends to abstract the use of threads, AsyncLocal instances can be used to persist data across threads.
The AsyncLocal class also provides optional notifications when the value associated with the current thread changes, either because it was explicitly changed by setting the Value property, or implicitly changed when the thread encountered an await or other context transition.

Should Semaphoreslim be in the controller instead of further down in the chain?

We have a deadlock like behaviour in our production-environment and I wonder if we use SemaphoreSlim correctly.
In our restapi the code looks like this:
public async Task<IActionResult> CreateAsync([FromBody] SomeModel someModel)
{
var result = await _someClass.CreateArende(someModel);
return result;
}
public async Task<IActionResult> RegisterAsync([FromBody] SomeModel someModel)
{
var result = await _someClass.RegisterArende(someModel);
return result;
}
No SemphoreSlim in controller level of our API but in someClass looks like this:
public class SomeClass
{
protected static SemaphoreSlim _semphoreSlimCreateArende = new SemaphoreSlim(1, 1);
public async virtual Task<SomeResponseDto> CreateArende(SomeModel someModel)
{
try
{
await _semphoreSlimCreateArende.WaitAsync();
}
finally
{
try
{
_semphoreSlimCreateArende.Release();
}
catch (Exception)
{
}
}
return new SomeResponseDto()
{
...
};
}
public async virtual Task<SomeResponseDto> RegisterArende(SomeModel someModel)
{
try
{
await _semphoreSlimCreateArende.WaitAsync();
}
finally
{
try
{
_semphoreSlimCreateArende.Release();
}
catch (Exception)
{
}
}
return new SomeResponseDto()
{
...
};
}
}
Should the SemaphoreSlim be in the controller level instead? Or should I change the controllers actions to not be async?
This question is a little disjointed, however lets try to make sense of it a little
Firstly lets get the pattern right
try
{
await _semphoreSlimCreateArende.WaitAsync();
// do your sync work here
}
finally
{
// if this throws you are certainly doing something wrong
_semphoreSlimCreateArende.Release();
}
Secondly, you should have your keyboard taken away from you for this
catch (Exception)
{
}
Don't ever blindly eat exceptions, and if you are getting them on _semphoreSlimCreateArende.Release you have serious problems already and you have to work out why
Should the semaphoreslim be in the controller level instead?
Use them at the level that makes the most sense, i mean if you need to sync a piece of code sync it there, not 13 levels up.
Or should i change the controllers actions to not be async?
if you have asnyc work make your controller async and let it propagate down the stack to your async code
We have a deadlock like behaviour in our production-environment and i
wonder if we use semaphoreslim correctly.
Woah, are we talking DataBase Deadlocks, or Context DeadLocks. Either way this all sounds a little fishy

Async task will not produce the good response

I'm trying to wait the end of function to perform some task. HEre is my architecture
A class for the windows service
A class for communication with a device, instanciated as "ilon". This class have access to another class, who permit me to use a webservice
From the windows service, i'm doing it :
Item_DataColl resultSet = ilon.read("Net/LON/10/LampDali1/nviRunHours");
Here is the definition of the read function of the "ilon" class:
internal Item_DataColl read(string UCPTName)
{
return ilonBind.invoke_command_READ("Net/LON/10/LampDali1/nviRunHours").Result;
}
Ilonbind variable is associated to a class who permit me to create a connection with the webservice. So he got a function named "invoke_command_read", defined as :
public async Task<Item_DataColl> invoke_command_READ(string UCPTName)
{
return await Task.Run(() => thread_command_READ_result(UCPTName));
}
On the same class, i finally have this function :
private Item_DataColl thread_command_READ_result(string UCPTName)
{
Item_DataColl resultSet = null;
if (UCPTName != null)
{
try
{
OnProgressBarUpdate(progressBar.UnknownEnd);
resultSet = connector.command_READ(UCPTName);
readOperationDone(resultSet);
OnConsoleWriting(string.Format("[READING] Lecture réussie : {0} = {1}", ((Dp_Data)resultSet.Item[0]).UCPTname, ((Dp_Data)resultSet.Item[0]).UCPTvalue[0].Value), ILonConnectorConsoleResultType.RESULT);
}
catch (Exception e)
{
OnConsoleWriting(e.ToString(), ILonConnectorConsoleResultType.ERROR);
}
finally
{
OnProgressBarUpdate(progressBar.Invisible);
}
}
return resultSet;
}
Instruction "resultSet = connector.command_READ(UCPTName)" work well, and no result will be return until the result of the webservice request. But i am not able to get any result of the webservice.
Are my Task used well ?
Are my Task used well?
No.
Here's what's going on:
The actual operation is a network call, so it's a perfect fit for async.
But the proxy gives you synchronous APIs, so you're blocking a thread. (not good)
So invoke_command_READ wraps the synchronous API in a Task.Run, so it blocks a thread pool thread. (not good)
Then read blocks on the task using Result, blocking two threads per request and causing a deadlock. (really bad)
Your code is sync-over-async-over-sync, which is notable for employing two anti-patterns (sync-over-async and async-over-sync) simultaneously.
To fix this, either go async all the way, or sync all the way. Async all the way is more efficient but requires async APIs on your proxy:
public async Task<Item_DataColl> invoke_command_READ(string UCPTName)
{
Item_DataColl resultSet = null;
if (UCPTName != null)
{
try
{
OnProgressBarUpdate(progressBar.UnknownEnd);
resultSet = await connector.command_READAsync(UCPTName);
readOperationDone(resultSet);
OnConsoleWriting(string.Format("[READING] Lecture réussie : {0} = {1}", ((Dp_Data)resultSet.Item[0]).UCPTname, ((Dp_Data)resultSet.Item[0]).UCPTvalue[0].Value), ILonConnectorConsoleResultType.RESULT);
}
catch (Exception e)
{
OnConsoleWriting(e.ToString(), ILonConnectorConsoleResultType.ERROR);
}
finally
{
OnProgressBarUpdate(progressBar.Invisible);
}
}
return resultSet;
}
internal Task<Item_DataColl> readAsync(string UCPTName)
{
return ilonBind.invoke_command_READ("Net/LON/10/LampDali1/nviRunHours");
}
Sync all the way would probably be easier, since your proxy is sync and your consuming code is sync:
internal Item_DataColl read(string UCPTName)
{
return ilonBind.invoke_command_READ("Net/LON/10/LampDali1/nviRunHours");
}
public Item_DataColl invoke_command_READ(string UCPTName)
{
return thread_command_READ_result(UCPTName);
}

Async command execution in MVVM light

I am wondering why MVVM light is missing command with async execution? I believe there are many cases where this could be useful, so let me name one.
Let's say that our UI contains one container that contains multiple screens. User can close a particular screen or a container with multiple screens. Let's say that a user has issued a close command on the container. Container in return invokes close command on each screen, and it needs to wait for screen to be closed. This in practice can means validating data. saving, etc. For this reason we need to issue an async call to keep the UI from becoming unresponsive, and also we need to wait for task to complete, in order to continue.
So, if we have something like this in Command
public RelayCommand CloseCommand
{
get { return _closeCommand ?? _closeCommand = new RelayCommand( async () =>
{
foreach (var screen in Screens)
{
if (!await screen.CloseCommand.ExecuteAsync(null))
{
// do something
}
}
}) }
}
We could also expose additional method on screen, but in my opinion it should be task of RelayCommand, since it already exist there.
Or there is a different methodology to handle such scenario?
Probably because there are many different ways of doing it; I describe a few approaches in my MSDN article on the subject.
Asynchronous lifetime commands are especially tricky. Something like a "close" command must be carefully considered. Is there some indication that a close is in progress? What happens if the user closes more than once ("close" in particular can often be initiated by an OS or another app even if a "close button" is disabled)?
I found this being in some ways a solution to making async commands in MVVM Light.
If fact it overwrap a async method with Task.Run. Our wrapped method has to verify if it not executed twice, and catches errors from lower async executions.
private bool isLoading;
public bool IsLoading
{
get { return isLoading; }
set
{
if (value != isLoading)
{
Set(ref isLoading, value);
//Used to refresh Commands CanExecute laying on IsLoading
CommandManager.InvalidateRequerySuggested();
}
}
}
private RelayCommand loadCommand;
public RelayCommand LoadCommand
{
get
{
return loadCommand ?? (loadCommand = new RelayCommand(
() => Task.Run(LoadAsync),
() => !IsLoading
));
}
}
private async Task LoadAsync()
{
//Prevents double execution in case of many mouse clicks on button
if (IsLoading)
{
return;
}
//Assignments which need to be done on UI tread
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsLoading = true;
});
try
{
list = await service.LoadAsync();
...
}
catch (Exception e)
{
...
}
finally
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsLoading = false;
});
}
}

Task chaining without TaskCompletionSource?

I'm converting some async/await code to chained tasks, so I can use it in the released framework. The await code looks like this
public async Task<TraumMessage> Get() {
var message = await Invoke("GET");
var memorized = await message.Memorize();
return memorized;
}
where
Task<TraumMessage> Invoke(string verb) {}
Task<TraumMessage> Memorize() {}
I was hoping to chain Invoke and Memorize to return the task produced by Memorize, but that results in a Task<Task<TraumMessage>. The solution i've ended up is a TaskCompletionSource<TraumMessage> as my signal:
public Task<TraumMessage> Get() {
var completion = new TaskCompletionSource<TraumMessage>();
Invoke("GET").ContinueWith( t1 => {
if(t1.IsFaulted) {
completion.SetException(t1.Exception);
return;
}
t1.Result.Memorize().ContinueWith( t2 => {
if(t2.IsFaulted) {
completion.SetException(t2.Exception);
return;
}
completion.SetResult(t2.Result);
});
});
return completion.Task;
}
Is there a way to accomplish this without the TaskCompletionSource?
Yes, the framework comes with a handy Unwrap() extension method for exactly what you want.
Invoke("GET").ContinueWith( t => t.Result.Memorize() ).Unwrap();
If you're doing cancellation then you'll need to pass cancel tokens into the appropriate places, obviously.
I think that's pretty much the only way to accomplish what you want. Chaining disparate Tasks together isn't supported by the continuation APIs, so you have to resort to using a TaskCompletionSource like you have to coordinate the work.
I don't have the Async CTP installed on this machine, but why don't you take a look at the code with a decompiler (or ILDASM if you know how to read IL) to see what it's doing. I bet it does something very similar to your TCS code under the covers.
You can use attached child tasks. The parent task will only transition into the completed status when all child tasks are complete. Exceptions are propagated to the parent task.
You will need a result holder, as the result will be assigned after the parent task's delegate has finished, but will be set when the parent tasks continuations are run.
Like this:
public class Holder<T> where T: class
{
public T Value { get; set; }
}
public Task<Holder<TraumMessage>> Get() {
var invokeTask = Invoke("GET");
var result = invokeTask.ContinueWith<Holder<TraumMessage>>(t1 => {
var holder = new Holder<TraumMessage>();
var memorizeTask = t1.Result.Memorize();
memorizeTask.ContinueWith(t2 => {
holder.Value = t2.Result;
}, TaskContinuationOptions.AttachedToParent);
return holder;
});
return result;
}

Categories