Task.Run() in C# doesn't execute some parts - c#

I want to do a task in background without freezing the main User Interface. However, I have some problem using Task.Run() with anonymous function in C# because it seems like it doesn't execute the code. I think my implementation may be incorrect.
private List<string> GetPdfList
{
get
{
return File.Directory.GetFiles(PDF_FILE_DIRECTORY);
}
}
private void InitializePdf()
{
if (GetPdfList.Count > 0)
{
foreach (var pdf in GetPdfList)
{
var converter = new PdfConvertor();
var format = ImageFormat.Png;
converter.Convert(pdf, TempFolder, format);
}
}
}
public MainForm()
{
InitializeComponent();
Task.Run(() =>
{
InitializePdf();
});
}
I think the problem is in foreach scope

Task.Run() creates the task, but doesn't execute it.
In order to do what you want, you should await for the task result in an async event.
See Async loading for winforms

Related

C# async await not working winforms ui freeze

How to use _Asyn methods correctly ?
With my limited experience with C#, I don't know why. How to improve it? Thanks in advance.
//use :
this.SyncDataDataGridView.DataSource = await patentLaunch.LoadAccessDbListAsync();
//Method-01 winfroms UI OK (use ToList() )
public async Task<List<SyncNotice>> LoadAccessDbListAsync01()
{
return await Task.Run(() =>
{
using (var context = new SyncDbContextContext())
{
return context.SyncNotices.OrderByDescending(m => m.Id).Take(1000).ToList();
}
});
}
//Method-02 winfroms UI freeze ! ( use ToListAsync() EntityFrameworkCore )
public Task<List<SyncNotice>> LoadAccessDbListAsync02()
{
using (var context = new SyncDbContextContext())
{
return context.SyncNotices.OrderByDescending(m => m.Id).Take(1000).ToListAsync();
}
}
my full code is:
private async void Form_Load(object sender, EventArgs e){
//init binding
await context.SyncNotices.LoadAsync();
this.SyncDataDataGridView.DataSource = context.SyncNotices.Local.ToBindingList();
}
//init event
patentLaunch.OnFolderAddAccessOk += () => {
Invoke(new Action(async () =>
{
this.SyncDataDataGridView.DataSource = await patentLaunch.LoadAccessDbListAsync02();
}));
};
};
}
//call in fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
//in patentLaunch.cs
public void AddSigleFloderToAccessDb(string folder, string syncStatus)
{
var now = DateTime.Now;
var entity = new SyncNotice
{
FolderName = folder,
CreateTime = now,
SyncStatus = syncStatus
};
using (var context = new SyncDbContextContext())
{
context.SyncNotices.Add(entity);
context.SaveChanges();
}
UpdateLastExecTime(now);
// send event
OnFolderAddAccessOk();
}
//in patentLaunch.cs
public event Action OnFolderAddAccessOk;
Thanks for JonasH . Thank you for your reply.
,finally I used mehtod01
Some databases do not support truly async queries. In that case queries may be synchronous even if there is a *Async-method.
I have not found any concrete documentation about access supporting or not supporting asynchronous queries. But based on its age, and the fact that your call is actually blocking, I would guess the chances are low.
So as far as I know you just have to use LoadAccessDbListAsync01 to avoid blocking.
Some databases do not support truly async queries. In that case queries may be synchronous even if there is a *Async-method.
I have not found any concrete documentation about access supporting or not supporting asynchronous queries. But based on its age, and the fact that your call is actually blocking, I would guess the chances are low.
So as far as I know you just have to use LoadAccessDbListAsync01 to avoid blocking.

ASP.NET - async programming

I am trying to understand async programming, and I had a question. It is regarding the following functions below.
public async void TestAsyncCall() {
Task<string> TaskResult1 = DoSomethingAsync();
string Result2 = DoSomething();
string Result1 = await TaskResult1;
}
public string DoSomething() {
return "synch";
}
public async Task<string> DoSomethingAsync() {
await Task.Delay(10000);
return "asynch";
}
In the function call TestAsyncCall(), would one thread be used to execute DoSomethingAsync(), and another thread to execute DoSomething()?
Then when await is encountered, it would wait for DoSomethingAsync() to complete and release that thread (while also not blocking the original thread)?
Or will this not warrant any new threads being created? In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?
I recommend you read my article on async ASP.NET.
Or will this not warrant any new threads being created?
This won't create any new threads. In particular, async and await by themselves won't create any new threads.
On ASP.NET, it's likely that the code after an await will run on a different thread than the code before that await. This is just exchanging one thread for another, though; no new threads are created.
In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?
The primary use case for async is to deal with I/O, yes. This is particularly true on ASP.NET.
As #Stepehen-cleary said, "In particular, async and await by themselves won't create any new threads."
This next example is taken from the book: "C sharp in Depth" by John Skeet, chapter 15 pp.465:
class AsyncForm : Form
{
/* The first part of listing 15.1 simply creates the UI and hooks up an event handler for
the button in a straightforward way */
Label label;
Button button;
public AsyncForm()
{
label = new Label {
Location = new Point(10, 20),
Text = "Length"
};
button = new Button {
Location = new Point(10, 50),
Text = "Click"
};
button.Click += DisplayWebSiteLength;
AutoSize = true;
Controls.Add(label);
Controls.Add(button);
}
/* When you click on the button, the text of the book’s home page is fetched
and the label is updated to display the HTML lenght in characters */
async void DisplayWebSiteLength(object sender, EventArgs e)
{
label.Text = "Fetching...";
using (HttpClient client = new HttpClient())
{
string text =
await client.GetStringAsync("http://csharpindepth.com");
label.Text = text.Length.ToString();
}
}
/* The label is updated to display the HTML length in characters D. The
HttpClient is also disposed appropriately, whether the operation succeeds or fails—
something that would be all too easy to forget if you were writing similar asynchronous
code in C# 4 */
}
With this in mind, let's take a look to your code, you have Result1 and Result2, there's no point in having one asynchronous task waiting for a synchronous task to be finished. I would use Parallelism so you can perform both methods but to return something like two sets of Data, performing LINQ queries at the same time.
Take a look to this short example about Parallelism with Async Tasks:
public class StudentDocs
{
//some code over here
string sResult = ProcessDocs().Result;
//If string sResult is not empty there was an error
if (!sResult.Equals(string.Empty))
throw new Exception(sResult);
//some code over there
##region Methods
public async Task<string> ProcessDocs()
{
string sResult = string.Empty;
try
{
var taskStuDocs = GetStudentDocumentsAsync(item.NroCliente);
var taskStuClasses = GetStudentSemesterClassesAsync(item.NroCliente, vencimientoParaProductos);
//We Wait for BOTH TASKS to be accomplished...
await Task.WhenAll(taskStuDocs, taskStuClasses);
//Get the IList<Class>
var docsStudent = taskStuDocs.Result;
var docsCourses = taskStuClasses.Result;
/*
You can do something with this data ... here
*/
}
catch (Exception ex)
{
sResult = ex.Message;
Loggerdb.LogInfo("ERROR:" + ex.Message);
}
}
public async Task<IList<classA>> GetStudentDocumentsAsync(long studentId)
{
return await Task.Run(() => GetStudentDocuments(studentId)).ConfigureAwait(false);
}
public async Task<IList<classB>> GetStudentSemesterCoursessAsync(long studentId)
{
return await Task.Run(() => GetStudentSemesterCourses(studentId)).ConfigureAwait(false);
}
//Performs task to bring Student Documents
public IList<ClassA> GetStudentDocuments(long studentId)
{
IList<ClassA> studentDocs = new List<ClassA>();
//Let's execute a Stored Procedured map on Entity Framework
using (ctxUniversityData oQuery = new ctxUniversityData())
{
//Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
foreach (var item in oQuery.GetStudentGrades(Convert.ToDecimal(studentId)).AsParallel())
{
//These are every element of IList
studentDocs.Add(new ClassA(
(int)(item.studentId ?? 0),
item.studentName,
item.studentLastName,
Convert.ToInt64(item.studentAge),
item.studentProfile,
item.studentRecord
));
}
}
return studentDocs;
}
//Performs task to bring Student Courses per Semester
public IList<ClassB> GetStudentSemesterCourses(long studentId)
{
IList<ClassB> studentCourses = new List<ClassB>();
//Let's execute a Stored Procedured map on Entity Framework
using (ctxUniversityData oQuery = new ctxUniversityData())
{
//Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
foreach (var item in oQuery.GetStudentCourses(Convert.ToDecimal(studentId)).AsParallel())
{
//These are every element of IList
studentCourses.Add(new ClassB(
(int)(item.studentId ?? 0),
item.studentName,
item.studentLastName,
item.carreerName,
item.semesterNumber,
Convert.ToInt64(item.Year),
item.course ,
item.professorName
));
}
}
return studentCourses;
}
#endregion
}

Async Task in WPF

I tried to run a task for a WPF UI Code Behind . but it doesn't work and noting happend when I use Task.Factory but it works when I use the code without Task.Factory
public MainWindow()
{
InitializeComponent();
GetNews();
}
private void GetNews()
{
Task.Factory.StartNew(() =>
{
FeedReader reader = new FeedReader();
var news = reader.RetrieveFeed("http://www.bbc.com/feed/");
foreach (var item in news)
{
textBlock.Text = item.Title;
}
});
}
How can I use async/await or anything that prevent block main thread?
Nothing happens because an exception is thrown as you are trying to modify UI element outside of UI thread. You should either use textBlock.Dispatcher.Invoke method or make FeedReader asynchronous and use async/await in your method, which is preferable.
So the prefered solution would be (provided RetrieveFeed is async method):
private async void GetNews()
{
FeedReader reader = new FeedReader();
var news = await reader.RetrieveFeed("http://www.bbc.com/feed/");
foreach (var item in news)
{
textBlock.Text = item.Title;
}
}
Alternatively you could wrap feed retrieval in a task, which will work with your current implementation:
private async void GetNews()
{
FeedReader reader = new FeedReader();
var news = await Task.Run(() => reader.RetrieveFeed("http://www.bbc.com/feed/"));
foreach (var item in news)
{
textBlock.Text = item.Title;
}
}
This approach will work because await will capture SynchronizationContext of UI thread and will set value to the textbox in UI thread.
And the caveat here is that exceptions thrown in async void method are never observed and are lost. So you should wrap the code inside GetNews method in try/catch block and at least log the exception so you are aware of it.
You can use the async version to retrieve the feed
SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct);
DisplayResults(feed);
Check the example from msdn.
It calls the Windows Runtime method, RetrieveFeedAsync, and applies a .NET Framework extension method, AsTask, to the returned IAsyncOperation instance. AsTask represents the instance as a Task, so that you can await it.

Async/Await - not understanding why one way is Blocking and another is not

Still trying to wrap my head around async/await. I have the following method for drag/drop loading:
private async void p_DragDrop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
List<string> CurvesToLoad = new List<string>();
List<string> TestsToLoad = new List<string>();
foreach (string file in files)
{
if (file.ToUpper().EndsWith(".CCC"))
CurvesToLoad.Add(file);
else if (file.ToUpper().EndsWith(".TTT"))
TestsToLoad.Add(file);
}
//SNIPPET IN BELOW SECTION
foreach (string CurvePath in CurvesToLoad)
{
Curve c = new Curve(CurvePath);
await Task.Run(() =>
{
c.load();
c.calculate();
});
AddCurveControls(c);
}
//END SNIPPET
foreach (string TestPath in TestsToLoad)
{
Test t = new Test(TestPath);
await Task.Run(() =>
{
t.load();
});
AddTestControls(t);
}
}
It is non-blocking as I expected - I am able to navigate between tabs of the TabControl as multiple items are loaded and I can see each tab pop up as it complete loading.
I then tried to convert to this:
private Task<Curve> LoadAndCalculateCurve(string path)
{
Curve c = new Curve(path);
c.load();
c.calculate();
return Task.FromResult(c);
}
And then replace the marked snippet from the first code block with:
foreach (string CurvePath in CurvesToLoad)
{
Curve c = await LoadAndCalculateCurve(CurvePath);
AddCurveControls(c);
}
And it becomes blocking - I can't navigate through tabs as it's loading, and then all of the loaded items appear at once when they are completed. Just trying to learn and understand the differences at play here - many thanks in advance.
EDIT:
Updated LoadAndCalculateCurve():
private async Task<Curve> LoadAndCalculateCurve(string path)
{
Curve c = new Curve(path);
await Task.Run(() => {
c.load();
c.calculate();
});
return c;
}
Async methods do not execute in a different thread, await does not start a thread. async merely enables the await keyword and await waits for something that already runs.
All of that code is running on the UI thread.
So basically this is what is happening to my knowledge.
In your first code you write
foreach (string CurvePath in CurvesToLoad)
{
Curve c = new Curve(CurvePath);
await Task.Run(() =>
{
c.load();
c.calculate();
});
AddCurveControls(c);
}
this does the async flow as expected because you are using the Task.Run which adds the work to the ThreadPool queue.
In your second try you don't do this and you are using the same task. Try to use the same logic of (Task.Run) in the second try and I think it will work
The implementation of your LoadAndCalculateCurve method is to synchronously create a Curve, synchronously load it and perform the calculation, and then return the result wrapped in a Task. Nothing about this is asynchronously. When you await it it will invoke the method, do all of the synchronous work to get the (already completed) task, and then add a continuation to that (already completed) task that will fire immediately.
When you instead use Task.Run you're scheduling those long running operations to take place in another thread and immediately returning a (not yet completed) Task that you can use to run code when it does eventually finish its work.

Async/Await Iterate over returned Task<IEnumerable<SomeClass>>

I want to use async/await when querying a database with a HTTP call in my WPF application. It's my first time using async/await, so if you see any obvious mistake, feel free to point them out.
The problem is, that im not able to iterate over the returned collecting anymore, because it's now a Task of <IEnumerable<SomeClass>>, and from what I found out, the Task doesn't implement IEnumerable/IEnumerator.
My code look like this: The method that calls the async/await method.
private void AddProjectDrawingAndComponentsFromServerToLocalDbAsync(CreateDbContext1 db, Project item)
{
var drawings = client.GetDrawingsAsync(item.ProjectId);
..... (waiting for GetDrawingsAsync to return, so i can iterate over the drawings)
db.SaveChanges();
}
The method GetDrawingsAsync:
public async Task<IEnumerable<Drawing>> GetDrawingsAsync(int projectId)
{
var drawings = Task.Factory.StartNew(() => _client.Get(new GetDrawingsReq() { ProjectId = projectId }));
return await drawings;
}
Back to the method that waits for the async method to finish:
private void AddProjectDrawingAndComponentsFromServerToLocalDbAsync(CreateDbContext1 db, Project item)
{
var drawings = client.GetDrawingsAsync(item.ProjectId); <-- The returned Task<Task<IEnumerable<Drawing>>
Drawing prj_drawing = null;
foreach (var draw in drawings)
{
prj_drawing = new Drawing() { DrawingKey = draw.DrawingKey, Name = draw.Name, ProjectId = item.ProjectId };
item.AddDrawing(prj_drawing);
db.Projects.Add(item);
}
db.SaveChanges();
}
How would I be able to convert the returned type Task<IEnumerable<Drawing>> to something that i can iterate over in the foreach loop.
To iterate over the result of the Task, you need to get the result of the Task. And to do that, you should use await. This means you should change AddProjectDrawingAndComponentsFromServerToLocalDbAsync() into an async method:
private async Task AddProjectDrawingAndComponentsFromServerToLocalDbAsync(
CreateDbContext1 db, Project item)
{
var drawings = await client.GetDrawingsAsync(item.ProjectId);
foreach (var draw in drawings)
{
// whatever
}
db.SaveChanges();
}
This means that AddProjectDrawingAndComponentsFromServerToLocalDbAsync() (which is BTW quite a bad name for a method, I think) now returns a Task, so you should probably change the method that calls it into an async method too. This leads to “async all the way”, but that's unavoidable.

Categories

Resources