Tag: async await

我如何使`await …`使用`yield return`(即在迭代器方法中)?

我现有的代码看起来类似于: IEnumerable GetStuff() { using (SqlConnection conn = new SqlConnection(connectionString)) using (SqlCommand cmd = new SqlCommand(sql, conn) { conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { SomeClass someClass = f(reader); // create instance based on returned row yield return someClass; } } } 看来我可以通过使用reader.ReadAsync()获益。 但是,如果我只修改一行: while (await reader.ReadAsync()) 编译器通知我await只能在标记为async方法中使用,并建议我将方法签名修改为: async Task<IEnumerable> GetStuff() 但是,这样做会使GetStuff()无法使用,因为: GetStuff()的主体不能是迭代器块,因为Task<IEnumerable>不是迭代器接口类型。 我确信我错过了异步编程模型的关键概念。 […]

异步/等待.NET的WebBrowser类的实现

长期读者,这里的第一次海报。 我的目标:在使用WebBrowser类时能够利用async / await。 由于WebBrowser.Navigate(string url)是一个异步方法,因此在触发LoadComplete事件之前无法检查html文档。 到目前为止,这是我的(工作)代码: public class AsyncWebBrowser { protected WebBrowser m_WebBrowser; private ManualResetEvent m_MRE = new ManualResetEvent(false); public void SetBrowser(WebBrowser browser) { this.m_WebBrowser = browser; browser.LoadCompleted += new LoadCompletedEventHandler(WebBrowser_LoadCompleted); } public Task NavigateAsync(string url) { Navigate(url); return Task.Factory.StartNew((Action)(() => { m_MRE.WaitOne(); m_MRE.Reset(); })); } public void Navigate(string url) { m_WebBrowser.Navigate(new Uri(url)); } […]

缺少非捕获Task.Yield迫使我使用Task.Run,​​为什么要这样做呢?

如果这个问题是基于意见的,请提前道歉。 这里已经讨论了缺少不捕获执行上下文的Task.Yield版本。 显然,此function在早期版本的Async CTP中以某种forms出现,但由于它很容易被滥用而被删除 。 IMO,这样的function可能像Task.Run本身一样容易被滥用。 这就是我的意思。 想象一下,有一个等待的SwitchContext.Yield API来调度ThreadPool上的延续,因此执行将始终在与调用线程不同的线程上继续。 我可以在下面的代码中使用它,它从UI线程启动一些CPU绑定的工作。 我认为这是一种在池线程上继续CPU绑定工作的便捷方式: class Worker { static void Log(string format, params object[] args) { Debug.WriteLine(“{0}: {1}”, Thread.CurrentThread.ManagedThreadId, String.Format(format, args)); } public async Task UIAction() { // UI Thread Log(“UIAction”); // start the CPU-bound work var cts = new CancellationTokenSource(5000); var workTask = DoWorkAsync(cts.Token); // possibly await for […]

如何使用异步方法正确编写Parallel.For

我将如何构造下面的代码,以便调用异步方法? Parallel.For(0, elevations.Count(), delegate(int i) { allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels)); });

Async和Await的工作原理

我试图了解Async和Await是如何工作的。 如何控制程序中的旅行。 这是我试图理解的代码。 public async Task MyMethod() { Task longRunningTask = LongRunningOperation(); //indeed you can do independent to the int result work here MySynchronousMethod(); //and now we call await on the task int result = await longRunningTask; //use the result Console.WriteLine(result); } public async Task LongRunningOperation() // assume we return an int from this long […]

使用await时Monitor.Exit上的SynchronizationLockException

我正在创建一段代码,从我们拥有的遗留系统中获取网页。 为了避免过多的查询,我正在缓存获得的URL。 我正在使用Monitor.Enter , Monitor.Exit和双重检查以避免该请求被发出两次,但是当使用Monitor.Exit释放锁时,我收到此exception: System.Threading.SynchronizationLockException was caught HResult=-2146233064 Message=Object synchronization method was called from an unsynchronized block of code. Source=MyApp StackTrace: at MyApp.Data.ExProvider.d__0.MoveNext() in c:\Users\me\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Data\ExProvider.cs:line 56 — End of stack trace from previous location where exception was thrown — at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at MyApp.Data.ExProvider.d__15.MoveNext() in c:\Users\me\Documents\Visual Studio […]

使用Task.ContinueWith的异步回调

我正试图用C#的async / await / continuewith来玩。 我的目标是必须有两个并行运行的任务,尽管哪个任务按顺序执行一系列操作。 为此,我计划有一个List代表并行运行的2个(或更多)任务,并在每个Task上使用ContinueWith我的问题是继续的回调似乎不会执行await taskList已经返回了。 为了总结,这里有一个示例来说明我期望发生的事情: class Program { static public async Task Test() { System.Console.WriteLine(“Enter Test”); await Task.Delay(100); System.Console.WriteLine(“Leave Test”); } static void Main(string[] args) { Test().ContinueWith( async (task) => { System.Console.WriteLine(“Enter callback”); await Task.Delay(1000); System.Console.WriteLine(“Leave callback”); }, TaskContinuationOptions.AttachedToParent).Wait(); Console.WriteLine(“Done with test”); } } 预期的产出是 Enter Test Leave Test Enter callback […]

可以从多个线程等待相同的任务 – 等待线程安全吗?

等待线程安全吗? 似乎Task类是线程安全的,所以我猜等待它也是线程安全的,但我还没有在任何地方找到确认。 线程安全也是定制awaiter的要求 – 我的意思是IsCompleted,GetAwaiter等方法? 即如果这些方法不是线程安全的,那么等待是否是线程安全的? 但是,我不希望很快就需要定制的等待者。 用户场景的一个示例:假设我有一个后台任务,它以异步方式返回结果,然后从多个线程使用: using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace scratch1 { class Foo { Task _task; public Foo() { _task = Task.Run(async () => { await Task.Delay(5000); return 5; }); } // Called from multiple threads public async Task Bar(int i) { return (await _task) + i; […]

我想等待抛出AggregateException,而不仅仅是第一个Exception

等待故障任务(具有exception集的任务)时, await将重新抛出存储的exception。 如果存储的exception是AggregateException ,它将重新抛出第一个并丢弃其余的exception。 我们如何使用await并同时抛出原始的AggregateException以便我们不会意外丢失错误信息? 注意,当然可以考虑使用hacky解决方案(例如,围绕await尝试catch,然后调用Task.Wait )。 我真的希望找到一个干净的解决方案。 这里最好的做法是什么? 我想过使用自定义awaiter,但内置的TaskAwaiter包含了许多魔法,我不知道如何完全重现。 它调用TPL类型的内部API。 我也不想重现所有这些。 如果你想玩它,这是一个简短的repro: static void Main() { Run().Wait(); } static async Task Run() { Task[] tasks = new[] { CreateTask(“ex1”), CreateTask(“ex2”) }; await Task.WhenAll(tasks); } static Task CreateTask(string message) { return Task.Factory.StartNew(() => { throw new Exception(message); }); } 在Run只抛出两个exception中的一个。 请注意,Stack Overflow上的其他问题无法解决此特定问题。 建议重复时请小心。

异步/等待,自定义awaiter和垃圾收集器

我正在处理托管对象在async方法中过早完成的情况。 这是一个业余爱好的家庭自动化项目(Windows 8.1,.NET 4.5.1),我向非托管第三方DLL提供C#回调。 在某个传感器事件时调用回调。 要处理事件,我使用async/await和一个简单的自定义awaiter(而不是TaskCompletionSource )。 我这样做的部分原因是为了减少不必要的分配数量,但主要是出于好奇心作为学习练习。 下面是我所拥有的非常剥离的版本,使用Win32计时器队列计时器来模拟非托管事件源。 让我们从输出开始: 按Enter退出… 服务员() 打勾:0 打勾:1 〜Awaiter() 打勾:2 打勾:3 打勾:4 请注意我的等待者在第二次打勾后如何最终确定。 这是出乎意料的。 代码(控制台应用程序): using System; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { class Program { static async Task TestAsync() { var awaiter = new Awaiter(); //var hold = GCHandle.Alloc(awaiter); WaitOrTimerCallbackProc callback = (a, b) => […]