How do you create an asynchronous method in C#?
2022/7/6 1:23:59
本文主要是介绍How do you create an asynchronous method in C#?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
How do you create an asynchronous method in C#?
问题
Every blog post I've read tells you how to consume an asynchronous method in C#, but for some odd reason never explain how to build your own asynchronous methods to consume. So I have this code right now that consumes my method:
private async void button1_Click(object sender, EventArgs e) { var now = await CountToAsync(1000); label1.Text = now.ToString(); }
And I wrote this method that is CountToAsync
:
private Task<DateTime> CountToAsync(int num = 1000) { return Task.Factory.StartNew(() => { for (int i = 0; i < num; i++) { Console.WriteLine("#{0}", i); } }).ContinueWith(x => DateTime.Now); }
Is this, the use of Task.Factory
, the best way to write an asynchronous method, or should I write this another way?
I'm asking a general question about how to structure a method. I just want to know where to start in turning my already synchronous methods into asynchronous ones. – Khalid Abuhakmeh Apr 17, 2013 at 15:30 OK, so what does a typical synchronous method do, and why do you want to make it asynchronous? – Eric Lippert Apr 17, 2013 at 15:32 Let's say I have to batch process a bunch of files and return a result object. – Khalid Abuhakmeh Apr 17, 2013 at 15:36 OK, so: (1) what is the high-latency operation: obtaining the files -- because the network could be slow, or whatever -- or doing the processing -- because it is CPU intensive, say. And (2) you still haven't said why you want it to be asynchronous in the first place. Is there a UI thread that you want to not block, or what? – Eric Lippert Apr 17, 2013 at 15:56 @EricLippert The example give by the op is very basic, it really doesn't need to be that complicated. – David B. Dec 15, 2015 at 20:05 Agreed with David. @EricLipper, I really feel this is perfect question with reasonable details. – Harshan Oct 16, 2021 at 17:56
回答1
I don't recommend StartNew
unless you need that level of complexity.
If your async method is dependent on other async methods, the easiest approach is to use the async
keyword:
private static async Task<DateTime> CountToAsync(int num = 10) { for (int i = 0; i < num; i++) { await Task.Delay(TimeSpan.FromSeconds(1)); } return DateTime.Now; }
If your async method is doing CPU work, you should use Task.Run
:
private static async Task<DateTime> CountToAsync(int num = 10) { await Task.Run(() => ...); return DateTime.Now; }
You may find my async
/await
intro helpful.
回答2
If you didn't want to use async/await inside your method, but still "decorate" it so as to be able to use the await keyword from outside, TaskCompletionSource.cs:
public static Task<T> RunAsync<T>(Func<T> function) { if (function == null) throw new ArgumentNullException(“function”); var tcs = new TaskCompletionSource<T>(); ThreadPool.QueueUserWorkItem(_ => { try { T result = function(); tcs.SetResult(result); } catch(Exception exc) { tcs.SetException(exc); } }); return tcs.Task; }
From here and here
To support such a paradigm with Tasks, we need a way to retain the Task façade and the ability to refer to an arbitrary asynchronous operation as a Task, but to control the lifetime of that Task according to the rules of the underlying infrastructure that’s providing the asynchrony, and to do so in a manner that doesn’t cost significantly. This is the purpose of TaskCompletionSource.
I saw it's also used in the .NET source, e.g. WebClient.cs:
[HostProtection(ExternalThreading = true)] [ComVisible(false)] public Task<string> UploadStringTaskAsync(Uri address, string method, string data) { // Create the task to be returned var tcs = new TaskCompletionSource<string>(address); // Setup the callback event handler UploadStringCompletedEventHandler handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion); this.UploadStringCompleted += handler; // Start the async operation. try { this.UploadStringAsync(address, method, data, tcs); } catch { this.UploadStringCompleted -= handler; throw; } // Return the task that represents the async operation return tcs.Task; }
Finally, I also found the following useful:
I get asked this question all the time. The implication is that there must be some thread somewhere that’s blocking on the I/O call to the external resource. So, asynchronous code frees up the request thread, but only at the expense of another thread elsewhere in the system, right? No, not at all.
To understand why asynchronous requests scale, I’ll trace a (simplified) example of an asynchronous I/O call. Let’s say a request needs to write to a file. The request thread calls the asynchronous write method. WriteAsync is implemented by the Base Class Library (BCL), and uses completion ports for its asynchronous I/O. So, the WriteAsync call is passed down to the OS as an asynchronous file write. The OS then communicates with the driver stack, passing along the data to write in an I/O request packet (IRP).
This is where things get interesting: If a device driver can’t handle an IRP immediately, it must handle it asynchronously. So, the driver tells the disk to start writing and returns a “pending” response to the OS. The OS passes that “pending” response to the BCL, and the BCL returns an incomplete task to the request-handling code. The request-handling code awaits the task, which returns an incomplete task from that method and so on. Finally, the request-handling code ends up returning an incomplete task to ASP.NET, and the request thread is freed to return to the thread pool.
Introduction to Async/Await on ASP.NET
If the target is to improve scalability (rather than responsiveness), it all relies on the existence of an external I/O that provides the opportunity to do that.
回答3
One very simple way to make a method asynchronous is to use Task.Yield() method. As MSDN states:
You can use await Task.Yield(); in an asynchronous method to force the method to complete asynchronously.
Insert it at beginning of your method and it will then return immediately to the caller and complete the rest of the method on another thread.
private async Task<DateTime> CountToAsync(int num = 1000) { await Task.Yield(); for (int i = 0; i < num; i++) { Console.WriteLine("#{0}", i); } return DateTime.Now; }
这篇关于How do you create an asynchronous method in C#?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-12-06使用Microsoft.Extensions.AI在.NET中生成嵌入向量
- 2024-11-18微软研究:RAG系统的四个层次提升理解与回答能力
- 2024-11-15C#中怎么从PEM格式的证书中提取公钥?-icode9专业技术文章分享
- 2024-11-14云架构设计——如何用diagrams.net绘制专业的AWS架构图?
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#