简体   繁体   中英

C# Task ContinueWith Not Working as Expected

How to wait until a previous method completes before continuing execution? I thought this would be easy, but it's not turning out that way. I must be doing something really dumb even though I've read lots of examples. In the following code, I can't let the GetDocVM() method execute until the AddUserDocuments() method finishes. Why? Because GetDocVM() won't pull in the records that were just added. I inherited this code and am trying to improve it.

ut.ModelJSON = await Task.Run(() => _userTransactionService.ConvertToModelJson(typeof(UserDocument).Name, "", transactionDocs)).ConfigureAwait(false);
var taskReturnsVoid = Task.Run(() => _genericUploadService.AddUserDocuments(ut, docs));
List<GenericUploadDocumentViewModel> viewModel = new List<GenericUploadDocumentViewModel>();
await taskReturnsVoid.ContinueWith((t) =>
           {
                 viewModel = GetDocVM();//I EXPECTED THIS TO WAIT TO BE EXECUTED
           });
return Json(viewModel, JsonRequestBehavior.AllowGet);  //GETTING HERE TOO SOON

I don't envy you as this looks an awfully bad code base, just these several lines suffer from multiple problems.

One of the biggest ones is that you shouldn't run CPU-bound work using Task.Run on ASP.NET. This is what Stephen Cleary writes about this :

Async and await on ASP.NET are all about I/O. They really excel at reading and writing files, database records, and REST APIs. However, they're not good for CPU-bound tasks. You can kick off some background work by awaiting Task.Run, but there's no point in doing so. In fact, that will actually hurt your scalability by interfering with the ASP.NET thread pool heuristics. If you have CPU-bound work to do on ASP.NET, your best bet is to just execute it directly on the request thread. As a general rule, don't queue work to the thread pool on ASP.NET.

(I recommend reading his articles as it's an excellent source of the async/await knowledge.)

So your code cleaned up:

ut.ModelJSON = _userTransactionService.ConvertToModelJson(typeof(UserDocument).Name, "", transactionDocs);
_genericUploadService.AddUserDocuments(ut, docs);
List<GenericUploadDocumentViewModel> viewModel = GetDocVM();
return Json(viewModel, JsonRequestBehavior.AllowGet);

However, I suspect that _genericUploadService.AddUserDocuments and GetDocVM do some I/O related work (like networking or DB access). If you want to improve the performance of your code, you should consider rewriting them as async, then you can have this:

ut.ModelJSON = _userTransactionService.ConvertToModelJson(typeof(UserDocument).Name, "", transactionDocs);
await _genericUploadService.AddUserDocumentsAsync(ut, docs);
List<GenericUploadDocumentViewModel> viewModel = await GetDocVMAsync();
return Json(viewModel, JsonRequestBehavior.AllowGet);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM