I am looking at using IObservable to get a response in a request-response environment within a c# async methods and replace some older callback based code, but I am finding that if a value is pushed (Subject.OnNext) to the observable but FirstAsync is not yet at the await, then the FirstAsync is never given that message.
Is there a straightforward way to make it work, without a 2nd task/thread plus synchronisation?
public async Task<ResponseMessage> Send(RequestMessage message)
{
var id = Guid.NewGuid();
var ret = Inbound.FirstAsync((x) => x.id == id).Timeout(timeout); // Never even gets invoked if response is too fast
await DoSendMessage(id, message);
return await ret; // Will sometimes miss the event/message
}
// somewhere else reading the socket in a loop
// may or may not be the thread calling Send
Inbound = subject.AsObservable();
while (cond)
{
...
subject.OnNext(message);
}
I cant put the await for the FirstAsync simply before I send the request, as that would prevent the request being sent.
The await will subscribe to the observable. You can separate the subscription from the await by calling ToTask:
public async Task<ResponseMessage> Send(RequestMessage message)
{
var id = Guid.NewGuid();
var ret = Inbound.FirstAsync((x) => x.id == id).Timeout(timeout).ToTask();
await DoSendMessage(id, message);
return await ret;
}
I took a closer look and there is a very easy solution to your problem by just converting hot into cold observable. Replace Subject with ReplaySubject. Here is the article: http://www.introtorx.com/content/v1.0.10621.0/14_HotAndColdObservables.html.
Here is the explanation:
The Replay extension method allows you take an existing observable
sequence and give it 'replay' semantics as per ReplaySubject. As a
reminder, the ReplaySubject will cache all values so that any late
subscribers will also get all of the values.
Related
I'm in a bit of a conundrum regarding multithreading.
I'm currently working on a real-time service using SinglaR. The idea is that a connected user can request data from another.
Below is a gist of what the request and response functions look like.
Consider the following code:
private readonly ConcurrentBag _sharedObejcts= new ConcurrentBag();
The request:
[...]
var sharedObject = new MyObject();
_sharedObejcts.Add(sharedObject);
ForwardRequestFireAndForget();
try
{
await Task.Delay(30000, sharedObject.myCancellationToken);
}
catch
{
return sharedObject.ResponseProperty;
}
_myConcurrentBag.TryTake(sharedObject);
[...]
The response:
[...]
var result = DoSomePossiblyVeryLengthyTaskHere();
var sharedObject = ConcurrentBag
.Where(x)
.FirstOrDefault();
// The request has timed out so the object isn't there anymore.
if(sharedObject == null)
{
return someResponse;
}
sharedObject.ResponseProperty = result;
// triggers the cancellation source
sharedObject.Cancel();
return someOtherResponse;
[...]
So basically a request is made to the server, forwarded to the other host and the function waits for cancellation or it times out.
The other hosts call the respond function, which adds the repsonseObject and triggers myCancellationToken.
I am however unsure whether this represents a race condition.
In theory, could the responding thread retrieve the sharedObject while the other thread still sits on the finally block?
This would mean, the request timed out already, the task just hasn't gotten around to removing the object from the bag, which means the data is inconsistent.
What would be some guaranteed ways to make sure that the first thing that gets called after the Task.Delay() call is the TryTake()call?
You don't want to have the producer cancel the consumer's wait. That's way too much conflation of responsibilities.
Instead, what you really want is for the producer to send an asynchronous signal. This is done via TaskCompletionSource<T>. The consumer can add the object with an incomplete TCS, and then the consumer can (asynchronously) wait for that TCS to complete (or timeout). Then the producer just gives its value to the TCS.
Something like this:
class MyObject
{
public TaskCompletionSource<MyProperty> ResponseProperty { get; } = new TaskCompletionSource<MyProperty>();
}
// request (consumer):
var sharedObject = new MyObject();
_sharedObejcts.Add(sharedObject);
ForwardRequestFireAndForget();
var responseTask = sharedObject.ResponseProperty.Task;
if (await Task.WhenAny(Task.Delay(30000), responseTask) != responseTask)
return null;
_myConcurrentBag.TryTake(sharedObject);
return await responseTask;
// response (producer):
var result = DoSomePossiblyVeryLengthyTaskHere();
var sharedObject = ConcurrentBag
.Where(x)
.FirstOrDefault();
// The request has timed out so the object isn't there anymore.
if(sharedObject == null)
return someResponse;
sharedObject.ResponseProperty.TrySetResult(result);
return someOtherResponse;
The code above can be cleaned up a bit; specifically, it's not a bad idea to have the producer have a "producer view" of the shared object, and the consumer have a "consumer view", with both interfaces implemented by the same type. But the code above should give you the general idea.
I have an API which needs to be run in a loop for Mass processing.
Current single API is:
public async Task<ActionResult<CombinedAddressResponse>> GetCombinedAddress(AddressRequestDto request)
We are not allowed to touch/modify the original single API. However can be run in bulk, using foreach statement. What is the best way to run this asychronously without locks?
Current Solution below is just providing a list, would this be it?
public async Task<ActionResult<List<CombinedAddressResponse>>> GetCombinedAddress(List<AddressRequestDto> requests)
{
var combinedAddressResponses = new List<CombinedAddressResponse>();
foreach(AddressRequestDto request in requests)
{
var newCombinedAddress = (await GetCombinedAddress(request)).Value;
combinedAddressResponses.Add(newCombinedAddress);
}
return combinedAddressResponses;
}
Update:
In debugger, it has to go to combinedAddressResponse.Result.Value
combinedAddressResponse.Value = null
and Also strangely, writing combinedAddressResponse.Result.Value gives error below "Action Result does not contain a definition for for 'Value' and no accessible extension method
I'm writing this code off the top of my head without an IDE or sleep, so please comment if I'm missing something or there's a better way.
But effectively I think you want to run all your requests at once (not sequentially) doing something like this:
public async Task<ActionResult<List<CombinedAddressResponse>>> GetCombinedAddress(List<AddressRequestDto> requests)
{
var combinedAddressResponses = new List<CombinedAddressResponse>(requests.Count);
var tasks = new List<Task<ActionResult<CombinedAddressResponse>>(requests.Count);
foreach (var request in requests)
{
tasks.Add(Task.Run(async () => await GetCombinedAddress(request));
}
//This waits for all the tasks to complete
await tasks.WhenAll(tasks.ToArray());
combinedAddressResponses.AddRange(tasks.Select(x => x.Result.Value));
return combinedAddressResponses;
}
looking for a way to speed things up and run in parallel thanks
What you need is "asynchronous concurrency". I use the term "concurrency" to mean "doing more than one thing at a time", and "parallel" to mean "doing more than one thing at a time using threads". Since you're on ASP.NET, you don't want to use additional threads; you'd want to use a form of concurrency that works asynchronously (which uses fewer threads). So, Parallel and Task.Run should not be parts of your solution.
The way to do asynchronous concurrency is to build a collection of tasks, and then use await Task.WhenAll. E.g.:
public async Task<ActionResult<IReadOnlyList<CombinedAddressResponse>>> GetCombinedAddress(List<AddressRequestDto> requests)
{
// Build the collection of tasks by doing an asynchronous operation for each request.
var tasks = requests.Select(async request =>
{
var combinedAddressResponse = await GetCombinedAdress(request);
return combinedAddressResponse.Value;
}).ToList();
// Wait for all the tasks to complete and get the results.
var results = await Task.WhenAll(tasks);
return results;
}
I am new to threading world of c#. I read there are different ways to do threading like sequential.
My scenario is below. Which one would be more suitable for the below.
I have list of complex objects. I will be making calls to PUT endpoint for each object [body of put] separately. There can be 1000 or more objects in the list. And I cannot pass all the objects at one and hence I have to pass each object in every call to the put endpoint. In this way, I have to make 1000 calls separately if there are 1000 objects.
Each put call is independent of each other while I have to store the properties of the response back from each call.
I was thinking to apply threading concept to above but not sure which one and how to do it.
Any suggestions would be greatly appreciated.
Thanking in advance.
As per the comments below,
Putting the method signatures here and adding more details.
I have IEnumerable<CamelList>. For each camel, I have to make a put request call and update the table from the response of each call. I will write a new method that will accept this list and make use of below 2 methods to make call and update table. I have to ensure, I am making not more than 100 calls at the same time and the API I am calling can be called by the same user 100 times per minute.
We have a method as
public Camel SendRequest(handler, uri, route, Camel); //basically takes all the parameters and provide you the Camel.
We have a method as public void updateInTable(Entity Camel); //updates the table.
HTTP calls are typically made using the HttpClient class, whose HTTP methods are already asynchronous. You don't need to create your own threads or tasks.
All asynchronous methods return a Task or Task<T> value. You need to use theawaitkeyword to await for the operation to complete asynchronously - that means the thread is released until the operation completes. When that happens, execution resumes after theawait`.
You can see how to write a PUT request here. The example uses the PutAsJsonAsync method to reduce the boilerplate code needed to serialize a Product class into a string and create a StringContent class with the correct content type, eg:
var response = await client.PutAsJsonAsync($"api/products/{product.Id}", product);
response.EnsureSuccessStatusCode();
If you want to PUT 1000 products, all you need is an array or list with the products. You can use LINQ to make multiple calls and await the tasks they return at the end :
var callTasks = myProducts.Select(product=>client.PutAsJsonAsync($"api/products/{product.Id}", product);
var responses = await Task.WhenAll(callTasks);
This means that you have to wait for all requests to finish before you can check if any one succeeded. You can change the body of Select to await the response itself :
var callTasks = myProducts.Select(async product=>{
var response=await client.PutAsJsonAsync($"api/products/{product.Id}", product);
if (!response.IsSuccessStatusCode)
{
//Log the error
}
return response.StatusCode;
});
var responses=await Task.WhenAll(callTasks);
It's better to conver the lambda into a separate method though, eg PutProductAsync :
async Task<HttpStatusCode> PutProduct(Product product,HttpClient client)
{
var response=await client.PutAsJsonAsync($"api/products/{product.Id}", product);
if (!response.IsSuccessStatusCode)
{
//Log the error
}
return response.StatusCode;
};
var callTasks = myProducts.Select(product=>PutProductAsync(product));
var responses=await Task.WhenAll(callTasks);
I'm going to suggest using Microsoft's Reactive Framework for this. You need to NuGet "System.Reactive" to get the bits.
Then you can do this:
var urls = new string[1000]; //somehow populated;
Func<string, HttpContent, IObservable<string>> putCall = (u, c) =>
Observable
.Using(
() => new HttpClient(),
hc =>
from resp in Observable.FromAsync(() => hc.PutAsync(u, c))
from body in Observable.FromAsync(() => resp.Content.ReadAsStringAsync())
select body);
var callsPerTimeSpanAllowed = 100;
var timeSpanAllowed = TimeSpan.FromMinutes(1.0);
IObservable<IList<string>> bufferedIntervaledUrls =
Observable.Zip(
Observable.Interval(timeSpanAllowed),
urls.ToObservable().Buffer(callsPerTimeSpanAllowed),
(_, buffered_urls) => buffered_urls);
var query =
from bufferedUrls in bufferedIntervaledUrls
from url in bufferedUrls
from result in putCall(url, new StringContent("YOURCONTENTHERE"))
select new { url, result };
IDisposable subscription =
query
.Subscribe(
x => { /* do something with each `x.url` & `x.result` */ },
() => { /* do something when it is all finished */ });
This code is breaking the URLs into blocks (or buffers) of 100 and putting them on a timeline (or interval) of 1 minute apart. It then calls the putCall for each URL and returns the result.
It's probably a little advanced for you now, but I thought this answer might be useful just to see how clean this can be.
working my way through all that is async / await (coming from threadpools) and I've hit an interesting challenge.
I have a TCP Server running in a WPF application that accepts clients and stores them in a List<> like such:
private List<Client> clients = new List<Client>();
while (running && clientCount <= maxClients)
{
Client client = new Client(await server.AcceptTcpClientAsync());
await client.WriteLineAsync("Connected to the Server!");
clients.Add(client);
clientCount++;
}
So what I want to do is iterate through the list of my Clients and if any data is received, I want to append it to a textbox. I realize this may not be the best way to achieve this, and I'm open to suggestions, but this is how I currently have it structured.
A button starts the loop and continuously calls and awaits AllReadLineAsync()
private async void btnStartReadLoopClick(object sender, RoutedEventArgs e)
{
btnStartReadLoop.IsEnabled = false;
while(server.clientCount > 0)
{
string text = await server.AllReadLineAsync();
txtOutputLog.AppendText("[client] " + text + "\n");
}
}
which is this function:
public async Task<string> AllReadLineAsync()
{
var tasklist = new List<Task<string>>();
foreach (var client in clients)
tasklist.Add(client.ReadLineAsync());
while (tasklist.Count > 0)
{
Task<string> finishedTask = await Task.WhenAny(tasklist);
if (finishedTask.Status == TaskStatus.RanToCompletion)
return await finishedTask;
tasklist.Remove(finishedTask);
}
return "Error: No task finished";
}
This function iterates through the list of clients and creates a List<Tast<string>> of all the ReadLineAsync() tasks.
At any given time, I may only have 1 or 2 clients actually sending data, so I can't WhenAll() and I've tried WhenAny() and WaitAny() without success.
Note to future googlers: WaitAny() is like Wait() and is blocking. Do not do this on a UI thread. Instead use WhenAny() and await it.
So my current implementation kind of works, but I can't figure out this bug where messages will build up from 1 client if the other clients don't send data.
TL;DR: Am I using WhenAny() correctly or is there a better way for me to await ReadLineAsync and pass the result to a textbox?
EDIT: Here's the behavior I'm seeing
I typed in this order: Left, Right, Left 2, Right 2, Left 3, Right 3
and it appears as if some messages are being dropped?
EDIT 2: I found the source of the code snippet I copied on the MSDN blog: https://blogs.msdn.microsoft.com/pfxteam/2012/08/02/processing-tasks-as-they-complete/
This code snippet is meant specifically to iterate through a list of tasks ensuring they all are completed. I don't care if tasks are duplicated though so I need to modify the code to always check the entire tasklist instead of removing any tasks.
it appears as if some messages are being dropped?
Yes. Because asynchronous work is started when you call their method (e.g., ReadLineAsync). When one of them completes (Task.WhenAny), your code abandons the other tasks. But they keep running - they're still reading from their sockets, and whatever they read is just going to be thrown away.
AFAIK, the behavior is undefined when you start reading from the same socket again - it's possible it may read what's next, or it's possible it may be queued. I do know that you're not supposed to do issue multiple reads from a socket (or any stream) simultaneously.
Sockets are not a perfect match to async, because they can send data at any time. You should use Rx or events instead. It's possible to make async work but it's extremely complex.
Alright so I figured out where I was going wrong and why my previous code didn't work.
First off, let's talk about what this code does, and why it doesn't work:
public async Task<string> AllReadLineAsync()
{
var tasklist = new List<Task<string>>();
foreach (var client in clients)
tasklist.Add(client.ReadLineAsync());
while (tasklist.Count > 0)
{
Task<string> finishedTask = await Task.WhenAny(tasklist);
if (finishedTask.Status == TaskStatus.RanToCompletion)
return await finishedTask;
tasklist.Remove(finishedTask);
}
return "Error: No task finished";
}
1) Creates a list of await ReadLineAsync()
2) While the size of that list is greater than 0, we wait for await any of the ReadLineAsync functions.
3) When we hit a Task that has finished, we return it's string, and exit the function
4) Any remaining ReadLineAsync functions that did not finish are still running, but we lost the reference to their instance.
5) This function loops, calling AllReadAsync() immediately after it finishes.
6) This causes us to try and access the StreamReady while it is still being awaited from step 4 - Thus throwing an excpetion.
Handling Multiple TcpClients with an Async TCP Server
Because of the structure of this, I could not come up with a way to use WhenAny() in my application. Instead I added this function to my Client Class:
public async Task<string> CheckForDataAsync()
{
if (!stream.DataAvailable)
{
await Task.Delay(5);
return "";
}
return await reader.ReadLineAsync();
}
Instead of awaiting ReadLineAsync(), we instead access the NetworkStream from the TcpClient, and we check if there is data available, if(!stream.DataAvailable), if there is not, we return early with an empty string, else we await ReadLineAsync() because we know we have incoming data, and we expect to receive the whole line.
We then replace the first function I talked about, AllReadLineAsync() With the following:
public async Task<string> AllReadLineAsync()
{
string data = "", packet = "";
foreach (var client in clients)
{
data = await client.CheckForDataAsync();
if (data != string.Empty)
packet += string.Format($"[client] {data}\n");
}
return packet;
}
Which is even simpler than the previous way I was trying. This now iterates through all of our clients in a for loop, and calls the CheckForDataAsync() function on each client. Since this functions returns early instead of infinitely awaiting a full ReadLineAsync() it does not continue to run in the background after the AllReadLineAysnc() function ends.
After we finish looping through all of our clients, we take our string packet and return it to the UI context, where we can then add our data to a text box as such:
private async void RecvData(object sender, RoutedEventArgs e)
{
while(server.hasClient)
{
string text = await server.AllReadLineAsync();
txtOutputLog.AppendText(text);
}
}
And that's it. That's how I'm handling multiple TcpClients from within a WPF application.
I have the following code:
var tasks = await taskSeedSource
.Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
.ToList()
.ToTask();
if (tasks.Count == 0)
{
return;
}
if (tasks.Contains(null))
{
tasks = tasks.Where(t => t != null).ToArray();
if (tasks.Count == 0)
{
return;
}
}
await Task.WhenAll(tasks);
Where taskSeedSource is a Reactive Observable. It could be that this code have many problems, but I see at least two:
I am collecting tasks whereas I could do without it.
Somehow, the returned tasks list may contain nulls, even though GetPendingOrRunningTask is an async method and hence never returns null. I failed to understand why it happens, so I had to defend against it without understanding the cause of the problem.
I would like to use the AsyncCountdownEvent from the AsyncEx framework instead of collecting the tasks and then awaiting on them.
So, I can pass the countdown event to GetPendingOrRunningTask which will increment it immediately and signal before returning after awaiting for the completion of its internal logic. However, I do not understand how to integrate the countdown event into the monad (that is the Reactive jargon, isn't it?).
What is the right way to do it?
EDIT
Guys, let us forget about the mysterious nulls in the returned list. Suppose everything is green and the code is
var tasks = await taskSeedSource
.Select(taskSeed => GetPendingOrRunningTask(taskSeed, ...))
.ToList()
.ToTask();
await Task.WhenAll(tasks);
Now the question is how do I do it with the countdown event? So, suppose I have:
var c = new AsyncCountdownEvent(1);
and
async Task GetPendingOrRunningTask<T>(AsyncCountdownEvent c, T taskSeed, ...)
{
c.AddCount();
try
{
await ....
}
catch (Exception exc)
{
// The exception is handled
}
c.Signal();
}
My problem is that I no longer need the returned task. These tasks where collected and awaited to get the moment when all the work items are over, but now the countdown event can be used to indicate when the work is over.
My problem is that I am not sure how to integrate it into the Reactive chain. Essentially, the GetPendingOrRunningTask can be async void. And here I am stuck.
EDIT 2
Strange appearance of a null entry in the list of tasks
#Servy is correct that you need to solve the null Task problem at the source. Nobody wants to answer a question about how to workaround a problem that violates the contracts of a method that you've defined yourself and yet haven't provided the source for examination.
As for the issue about collecting tasks, it's easy to avoid with Merge if your method returns a generic Task<T>:
await taskSeedSource
.Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
.Where(task => task != null) // According to you, this shouldn't be necessary.
.Merge();
However, unfortunately there's no official Merge overload for the non-generic Task but that's easy enough to define:
public static IObservable<Unit> Merge(this IObservable<Task> sources)
{
return sources.Select(async source =>
{
await source.ConfigureAwait(false);
return Unit.Default;
})
.Merge();
}