C
C#3mo ago
Relevant

Long running process in Blazor Server

I have a Blazor Server app, and I have a page that will kick off a long running process. I am calling an async method without an await in order to get the response back quickly, and it is starting the processes fine. But it seems like whenever there is a long running syncronous task running in the background, it will lock the UI thread. How can I make this process run in a way that doesn't block the UI thread? Here's a sample project to show what I mean:
public class TestService
{
public void StartLongRunningJob()
{
LongRunningJob();
}

private async Task LongRunningJob()
{
while (true)
{
Thread.Sleep(5000); //Simulation of something that locks UI thread
await Task.Delay(1);
}
}
}
public class TestService
{
public void StartLongRunningJob()
{
LongRunningJob();
}

private async Task LongRunningJob()
{
while (true)
{
Thread.Sleep(5000); //Simulation of something that locks UI thread
await Task.Delay(1);
}
}
}
@inject TestService TestService

<button class="btn btn-primary" @onclick="HandleButtonClick">Start Long Running Job</button>

@code{
private void HandleButtonClick()
{
TestService.StartLongRunningJob();
}
}
@inject TestService TestService

<button class="btn btn-primary" @onclick="HandleButtonClick">Start Long Running Job</button>

@code{
private void HandleButtonClick()
{
TestService.StartLongRunningJob();
}
}
40 Replies
Relevant
Relevant3mo ago
Every time the loop hits the await, it does return control back to the UI, but then it locks again the next time it does the Thread.Sleep(5000) I looked into using BackgroundServices, but not sure if that's what I need in this case, since it's not something that is always running while the application is running, but only when a job is submitted
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
SpReeD
SpReeD3mo ago
I'm not exactly sure what you wanna achieve, but starting LongRunningJob doesn't make it run on a different Thread just being marked as async. You need to create a new Thread, either by the low-level Thread class or, better, by creating a Task, something like Task.Run(() => LongRunningJob);
Relevant
Relevant3mo ago
Yeah, I guess I don't have much concept of what "background" means
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
So Task.Run is different than just calling a method with no await, I assume?
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Yeah, that's what I'm asking, I mean. What do I use to offload that?
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
SpReeD
SpReeD3mo ago
Yes, it does create an actual new Thread; you can check this by setting a Thread.Current.Name = "Foobar" and pause the process in Debug. You'll see all the running Threads, one will be named Foobar.
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
I gotcha. I guess I always assumed that I only needed to do Task.Run if I was trying to run a sync method as async
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Yeah, I don't use Thread in a real world situation, was just looking for something that would lock syncronously
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Well I'll try out Task.Run and I assume that'll do what I was trying to do
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Thanks to you both
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
No, I don't
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Sweet, thanks
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Oh cool, I'm interested in knowing more about that, so I'll look more into Enqueue for backgroundQueue
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Ahh Channel, I think a friend told me about that, and I couldn't remember the class
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Oh neat, then just write to the channel with a new job request?
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Cool, that's not too complicated
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Relevant
Relevant3mo ago
Yeah, that's what I'm doing now anyways. I'm just using a SemaphoneSlim as a queue, but maybe that would be better
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
SpReeD
SpReeD3mo ago
To make it a bit more clearer, here's what I mean:
Task.Run(() =>
{
Thread.CurrentThread.Name = "foobar123";
Thread.Sleep(Timeout.Infinite);
});
Task.Run(() =>
{
Thread.CurrentThread.Name = "foobar123";
Thread.Sleep(Timeout.Infinite);
});
Will show up in the List, Debug->Windows->Threads
No description
SpReeD
SpReeD3mo ago
As seen, it's not blocking the Main Thread/UI Thread. When working with Threads and alike, it's very helpful to have the Threads window open in the debugger, it let you identify in which Thread you're currently in and so on.
Relevant
Relevant3mo ago
Oh neat, I'll have to watch that
Relevant
Relevant3mo ago
No description
Relevant
Relevant3mo ago
Seems to be working for now as I expected. May need to play around with my hacky queueing functionality, but for now, it's not locking my UI thread, so I'm happy
SpReeD
SpReeD3mo ago
To make it even more clearer; Task is just a wrapper for Thread. Thread is rarely used these days and considered being low-level, it's useful when in need to set the ApartmentState, etc. - Yes, as @TeBeClone mentioned, today you use Task in 99% of the cases. Task handles a lot of things you had to do yourself when using the Thread class.