I have a scenario in which I have to fetch xml file of customer from api call and then save it in my computer on first request and after that every request of that customer will use my computer file to get data of particular customer.
for example if I have two customers ABC and XYZ. let say first request come for ABC I want to start downloading file of ABC. while downloading is in progress let say first request of XYZ comes. I want to proceed downloading of XYZ customer file as well. but lets say while downloading is in progress for ABC and another request of ABC comes I should let it wait till file of ABC is downloading and after the file will be download I want to get data of 2nd request from that file.
I think about 2 solutions for eg if I lock code of downloading
// code
lock(obj)
{
DownloadXmle("ABC");
}
// code
2nd option is if I declare a static list and before downloading file i push customer number in that list and for all other requests of that customer it checks if institution number is in that list it should wait
//code
currentlyDownloadingFileList.add("ABC");
DownloadXmle("ABC");
currentlyDownloadingFileList.Remove("ABC");
//code
is there any better thing for that?
You should use a ConcurrentDictionary<string, object> to store a thread-safe map of customers to lock objects.
Use GetOrAdd() to safely get a lock object for the customer, then lock on that object.
To my mind it is better to use TPL. DownloadXmle should be asynchronous method which is returning Task<T> or just Task. It will help you to have better resources utilization and will give you powerful tool for your task. Let's look at your method implementation in that case:
public async Task DownloadXmleAsync(string customer)
{
...
}
Next when you will call you method you should save returning task somewhere:
Task taskAbc = DownloadXmleAsync("ABC");
When you will get new request for this customer you should do next:
taskAbc = taskAbc.ContinueWith(prevTask => DownloadXmleAsync("ABC"));
ContinueWith will schedule your next call and will run it only after first request will be finished. Second task will run in any case. taskAbc will be a link to a second task. Every time you will get new request it will scheduled.
Related
I have built a MQTT client that listens for certain status data. For each message I run a method which can take a while (up to 1 second). Since a lot of messages can arrive at once, I want to run the whole thing in parallel. My problem now is, when I receive a message belonging to topic A, I want to make sure that the previous task belonging to topic A has already finished before I start the new one. But I also need to be able to receive new messages during the time I am waiting for Task A to finish and add them to the queue if necessary. Of course, if the new message belongs to topic B, I don't care about the status of task A and I can run this method call in parallel.
In my mind, this is solved with a kind of dictionary that has different queues.
What about to use a lock on an object related to the topic?
When a new item come in the system you could retrieve/create a lock object from a ConcurrentDictionary and then you could use this object to lock the execution.
something like this.
static ConcurrentDictionary<string,object> _locksByCategory =
new ConcurrentDictionary<string,object>();
async void ProcessItem(ItemType item) {
var lockObject = _locksByCategory(item.Category, new object(), (k, o) => o);
lock (lockObject) {
// your code
}
}
This isn't a production ready solution but could help to start with.
I don't know exactly how you would do it, but it goes along the lines of:
On startup, create a (static? singleton?) Dictionary<Topic, ConcurrentQueue> and for each topic create a thread that does the following:
Wrap the ConcurrentQueue in a BlockingCollection
infinitely loop with BlockingCollection.Take at the start of the loop. This should block until an item is ready, execute the rest of the loop and listen for more items afterwards.
Whenever a message comes in, add it to the corresponding ConcurrentQueue.
Let's say we have an entity Team with fields Id, Name, Points and CompetitionId.
Based on this entity, I have a list saved in memory, with aggregate data for each team.
When I add some results, some lines in the table Teams, I want also to update this list, but not to wait for its result.
public async Task AddResults(List<Team> teams) {
await context.AddRange(teams);
await inMemoryService.SetRanking();
}
Inside of SetRankings method I get the teams lines from context and build the aggregate data. But I don't want to wait for that to be finished because is a long process (take ~ 10 minutes and will be increased each time). For that, I tried two methods:
1: to not use await keyword:
_ = inMemoryService.SetRanking(); this works only because I'll not wait for the task to be completed. BUT, the new aggregated list from memory will be created on the another thread (I think), and when I'll try to get the data, I'll receive the old one.
2: using ConfigureAwait with false value:
await inMemoryService.SetRanking().ConfigureAwait(false) here, the request is still locked until this task is completed.
How can I solve this? thx
The best way to not wait for a task to be completed is to give that task to another piece of code.
AddResults could add the work to a queue and return. Then, another piece of code processes that work.
The queue itself can be:
and in-memory queue,
a queue service that your chose cloud provider offers,
even a database table.
The 'another piece of code' which monitors and processes the queue could be:
a dedicated long running task in the same app
another service (e.g Azure Function with a queue trigger)
I have the below method in my FileController:
[HttpPost]
[NoAsyncTimeout]
public ActionResult FileGenerator(FileViewModel model) {
...
_fileGenerator.CreateFile(model.Id,model.location);
...
}
The method CreateFile is defined below:
public void CreateFile(int residentId, string location){
...
var caller = new AsyncMethodCaller(GenerateFilesAsync);
caller.BeginInvoke(residentId,location, new
AsyncCallback(GenerateFilesCallBack));
...
}
From what I know, AsyncMethodCaller and BeginInvoke is to process the file creation into a different
Thread so that it does not block the interface. The above method is being called by a web application
and several users can make requests to the controller Action FileGenerator - this will process the
file generation concurrently (may be in multiple thread).
I want to implement a mechanism to process the requests on a FIFO basis - i.e if a user accesses the web application
and invokes the function FileGenerator, while this file is being generated - another user from a different PC invokes
the function at the same time, his request should be queued and executed after the first user file is generated.
Is there any mechanism or method in MVC to queue controller Action requests from users?
You can leverage the Queue Class in C#. Instead of spawning an new thread for each request I would suggest using a single thread to monitor the queue and call the FileGenerator method to create file. You will also not need to make it async in this case.
So whenever a user access the controller method, it will place the model into queue. The thread which is monitoring the queue will process it whenever it has some models in it.
This is probably a crude way for Queue Management :)
Better way would be to use a standard Queuing Mechanisms MSMQ, but then again depends on the complexity of the application and required scalability.
I want to create a async method which will open a thread and complete several tasks that is relatively independent to the current http request (for example, sending emails and generating files both of which takes time)
I created the following method
private static async Task<T> DoSeparateTask<T>(Func<T> func)
{
return func();
}
and want to use it in such a way:
private static void DoSomething()
{
#step 1 - some code for immediate processing
#step 2 - some code for generating documents which takes time
var additionalDocumentGenerationWork = DoSeparateTask<Document>(() =>{
#additional code for generating Document
#even though it returns Document, but 99% time it wont be used in this method
});
#step 3 - some code for sending SMTP email which takes time
var additionalDocumentGenerationWork = DoSeparateTask<bool>(() =>{
#additional code for sending email
return true;
});
}
Everything compiles, however when I run the web application, it still keeps loading and waiting everything to complete before rendering the web page. As the 2 additional tasks (email and documents) are not relevant for displaying the webpage, how can I achieve such by using the async modifiers?
Or if my understanding of async is wrong... please help me to correct...
Many thanks.
Or if my understanding of async is wrong... please help me to correct...
As I explain on my blog, async does not change the HTTP protocol. At the end of the day, you only have one response for each request. To put another way, async yields to the thread pool, not to the client.
What you're looking for is a way to do operations outside the request/response lifecycle, which is not directly supported by ASP.NET. I describe a few approaches on my blog. The best (most reliable) approach is to place the work into a queue, and have an independent backend that processes the queue (such as an Azure worker role).
You don't need the DoSeparateTask<T>() method. Instead, just use Task.Run<T>():
private static async Task DoSomething()
{
// #step 1 - some code for immediate processing
// #step 2 - some code for generating documents which takes time
var additionalDocumentGenerationWork1 = await Task.Run(() =>
{
// #additional code for generating Document
// #even though it returns Document, but 99% time it wont be used in this method
});
// #step 3 - some code for sending SMTP email which takes time
var additionalDocumentGenerationWork2 = await Task.Run(() =>
{
// #additional code for sending email
return true;
});
}
Note that the type of additionalDocumentGenerationWork1 and additionalDocumentGenerationWork2 (you used the same name twice in your example, so I changed it above to make the code legal) are Document and bool respectively. You can use additionalDocumentGenerationWork1 in your second task invocation if you like (e.g. to pass the result of the first operation).
Im dealing with a scenario in C#.net where Im loading a page, and during that pageload event, a service is being called to populate a value which is used to diplay on the page.
The page also has other fields. So the issue here is, the service usually takes between 30 to 60 secs to return the value, other fields cannot be selected until this service returns a value. So there is also a "SAVE" button which cannot be clicked since we are still waiting on this service to return the value.
The problem im trying to solve here is, ideally, on pageload, I want this service to run on the background and let other fields populate the value and I should be able to execute other events like SAVE, NEXT PAGE, PREVIOUS PAGE etc when called.
The purpose of the value returned by the service is for reference only. The code does not have any dependency on this value.
If your service has a method call it by making your onpageload callback async and await the asynchronous method inside of it.
If the service does not have an async method to call you can create your own e.g:
public string DownloadStringAsync()
{
return "Test data";
}
public async Task<string> ReceiveStringAsync()
{
return await Task<string>.Run(() =>
{
//Method to download your data
return DownloadStringAsync();
});
}
and await it in your page load: sting data = await ReceiveStringAsync();
You are not providing enough information/code for a better answer.
You can try executing it in a Thread. Something like this
Thread runner = new Thread(() =>
{
// run service call here
});
runner.IsBackground = true;
runner.Start();
But in C# 4.0 there is the new Task Parallelism Library so you can read about that and proceed from there, technically a Task is like a thread, but the difference is that the Task can have continuation aswell as it manages the Thread pool.
Read TPL here: Task Parallelism Library