Tag: 异步

如何通过reflection判断C#方法是否异步/等待?

例如 class Foo { public async Task Bar() { await Task.Delay(500); } } 如果我们反思这个类和方法,我如何确定这是否是一个真正的async / await方法,而不仅仅是一个碰巧返回任务的方法? class Foo { public Task Bar() { return Task.Delay(500); } }

定制等待傻瓜

在Async / Await FAQ中 ,Stephen Toub说: 等待是暴露GetAwaiter方法的任何类型,该方法返回有效的awaiter 。 … awaiter是从等待的GetAwaiter方法返回的任何类型,并且符合特定模式。 因此,为了成为awaiter ,类型应该: 实现INotifyCompletion接口。 提供名为IsCompleted的布尔属性。 提供一个无参数的GetResult方法,该方法返回void或TResult 。 ( 我现在忽略了ICriticalNotifyCompletion 。 ) 我知道我提到的页面有一个示例,显示编译器如何转换等待操作,但我很难理解。 当我等待等待 时 , 何时检查IsCompleted ? 我应该在哪里设置它? 何时被OnCompleted调用? 哪个线程调用OnCompleted ? 我看到了直接调用OnCompleted的continuation参数和在不同示例中使用Task.Run(continuation)的示例,我应该选择哪个以及为什么?

提供异步串口通信

目前,我们的应用程序通过串口连接到Arduino。 我们发送一些ASCII格式的命令,并得到相同的回报。 为此,我们有一个命令队列,一个专门用于将这些命令写入端口的线程,以及一个专门用于读取和处理所有传入回复的线程。 类本身负责调度回复,这给了它太多的责任(应该只负责端口操作,而不是业务逻辑)。 我们宁愿以异步方式执行此操作。 系统中的任何内容都可以发送带有回调函数和超时的命令。 如果串口得到正确答复,则调用回调函数。 否则,它会超时并可能调用第二个回调(或者可能是带有succeeded?标志的单个回调)。 但是,我们只使用异步方法(特别是在Web操作中),而不是编写这样的系统。 谁能给我们一些关于如何进行的指示? 我们当前的计划是存储这些命令的队列。 在任何回复时,如果找到相关联的命令(通过比较ASCII值),它将被出列并执行回调。 计时器将定期检查超时,出队并执行适当的回调。 这似乎是一个简单的解决方案,但支持这一点的代码数量正在大幅增加,我们希望确保没有更好的内置解决方案或最佳实践。 编辑 :为了进一步澄清,这个特定的类是一个单例(无论好坏),还有许多其他线程可以访问它。 例如,一个线程可能想要请求传感器值,而另一个线程可能正在控制电机。 这些命令及其相关的回复不是以线性方式发生的; 时机可能会逆转。 因此,传统的生产者 – 消费者模式是不够的; 这更像是一个调度员。 例如,让我们调用这个单例类Arduino 。 Thread A正在运行,并且想要发送命令”*03″ ,因此它调用Arduino.Instance.SendCommand(“*03″) 。 同时, Thread B发送命令”*88” ,这两个命令都是近实时发送的。 一段时间之后, Arduino的SerialPort.Read()线程获取*88的回复然后回复*03 (即以相反的顺序发送它们)。 我们如何允许Thread A和Thread B正确阻止等待特定的回复进来? 我们假设我们将在每个线程中使用AutoResetEvent ,并使用异步回调让我们设置它。

我以为还在等待与调用者相同的线程,但似乎没有

我认为关于async / await的一点是,当任务完成时,继续在调用await时在相同的上下文上运行,在我的情况下,这将是UI线程。 例如: Debug.WriteLine(“2: Thread ID: ” + Thread.CurrentThread.ManagedThreadId); await fs.ReadAsync(data, 0, (int)fs.Length); Debug.WriteLine(“3: Thread ID: ” + Thread.CurrentThread.ManagedThreadId); 我不指望这个: 2: Thread ID: 10 3: Thread ID: 11 是什么赋予了? 为什么延续的线程ID与UI线程不同? 根据这篇文章 [^]我需要显式调用ConfigureAwait来改变连续上下文的行为!

.NET:我是否需要在异步下载时保留对WebClient的引用?

我在一段生产代码中使用以下方法: private void DownloadData(Uri uri) { WebClient webClient = new WebClient(); DownloadDataCompletedEventHandler eh = null; eh = delegate(object sender, DownloadDataCompletedEventArgs e) { webClient.DownloadDataCompleted -= eh; ((IDisposable) webClient).Dispose(); OnDataDownloaded(); }; webClient.DownloadDataCompleted += eh; webClient.DownloadDataAsync(uri); } 我现在担心,在调用DownloadDataCompleted事件之前, WebClient实例被垃圾收集可能导致难以重现的错误:退出我的DownloadData()方法后,没有对WebClient对象的明显引用,因此可能会发生这种情况。 所以我的问题是:这可以实际发生吗? 我无法重现该问题,因此可能会发生一些内部事情阻止WebClient对象被垃圾收集(例如,对象可能在等待响应时在某处注册自己的全局对象)。 代码在.NET 2.0上运行,如果这有任何区别。

async-await threading internals

我很好奇异步等待线程内部。 每个人都声明async在性能方面要好得多,因为它释放了等待长异步调用响应的线程。 好的我明白了。 但让我们考虑一下这种情况。 我有一个异步方法在数据库上执行异步操作。 数据库的api公开函数BeginQuery和事件QueryCompleted。 我用任务包装了那些(使用TaskCompletionSource)。 我的问题是调用BeginQuery和触发事件QueryCompleted之间的内幕。 我的意思是 – 它不需要产生某种工人来解雇事件吗? 在非常低的级别,它必须是一些阻止来自db的线程读取结果的同步循环。 我想是任何异步调用都必须生成一个线程来实际处理响应(可能在驱动程序代码中的低级c ++循环中等待它)。 因此,我们唯一的“收获”是当其他一些线程正在执行其工作时,可以释放调用者线程。 调用异步方法总是创建一个新的工作线程吗? 有人可以证实我的理解吗?

将CurrentCulture保持在异步/等待状态

我有以下伪代码 string GetData() { var steps = new List<Task> { DoSomeStep(), DoSomeStep2() }; await Task.WhenAll(steps); return SomeResourceManagerProxy.RetrieveValuesForLocalizedStrings( steps.Select(s => s.Result) ); } 从WebService调用此方法,我根据用户的浏览器设置设置Thread.CurrentUICulture 。 等待之后, CurrentUICulture丢失了(我在不同的线程上运行)。 我用以下方法解决了这个问题: public class MyAwaiter : INotifyCompletion { private TaskAwaiter waiter; private CultureInfo culture; public MyAwaiter(TaskAwaiter waiter) { this.waiter = waiter; } public PreserveCultureAwaiter GetAwaiter() { return this; } public […]

HttpContext.Current在异步Callback中为null

尝试在方法回调中访问HttpContext.Current ,所以我可以修改Session变量,但是我收到HttpContext.Current为null的exception。 当_anAgent对象触发它时,异步触发回调方法。 在查看SO上的类似 问题之后,我仍然不确定解决方案。 我的代码的简化版本如下所示: public partial class Index : System.Web.UI.Page protected void Page_Load() { // aCallback is an Action, triggered when a callback is received _anAgent = new WorkAgent(…, aCallback: Callback); … HttpContext.Current.Session[“str_var”] = _someStrVariable; } protected void SendData() // Called on button click { … var some_str_variable = HttpContext.Current.Session[“str_var”]; // The agent […]

从Windows服务调用异步方法

我有一个用C#编写的Windows服务,可以定期激活后台作业。 通常,在任何给定时间,几十个重度I / O绑定任务(下载大文件等)并行运行。 该服务在一个相对繁忙的Web服务器上运行(目前是必需的),我认为在线程保护方面可以尽可能地使用异步API。 大部分工作都已完成。 所有作业现在完全异步(利用HttpClient等),主要作业循环(使用大量Task.Delay)也是如此。 剩下的就是弄清楚如何从服务的OnStart正确安全地启动主循环。 实际上,这是一个备受关注的呼叫异步同步困境。 以下是我到目前为止(非常简化)。 在Program.cs中: static void Main(string[] args) { TaskScheduler.UnobservedTaskException += (sender, e) => { // log & alert! e.SetObserved(); }; ServiceBase.Run(new MyService()); } 在MyService.cs中: protected override void OnStart(string[] args) { _scheduler.StartLoopAsync(); // fire and forget! will this get me into trouble? } 这是对我的调用StartLoopAsync 。 我不能简单地在返回的Task上使用Wait() ,因为OnStart需要相对快速地返回。 (作业循环需要在一个单独的线程上运行。)想到几个想法: […]

了解Silverlight Dispatcher

我有一个无效的跨线程访问问题,但有一点研究,我设法通过使用Dispatcher修复它。 现在在我的应用程序中,我有延迟加载的对象。 我使用WCF进行异步调用,像往常一样,我使用Dispatcher更新我的对象DataContext,但它不适用于这种情况。 不过我在这里找到了解决方案。 这是我不明白的。 在我的UserControl中,我有代码在我的对象上调用Toggle方法。 对此方法的调用在Dispatcher中是这样的。 Dispatcher.BeginInvoke( () => _CurrentPin.ToggleInfoPanel() ); 正如我之前提到的,这还不足以满足Silverlight。 我必须在我的对象中进行另一个 Dispatcher调用。 我的对象不是UIElement ,而是一个处理所有自己的加载/保存的简单类。 所以问题是通过调用来解决的 Deployment.Current.Dispatcher.BeginInvoke( () => dataContext.Detail = detail ); 在我class上。 为什么我必须两次调用Dispatcher来实现这一目标? 高级电话不应该足够吗? 在UIElement中Deployment.Current.Dispatcher和Dispatcher之间有区别吗?