相关疑难解决方法(0)

如何防止Task上的同步延续?

我有一些库(套接字网络)代码,它Task基于提供基于API的待处理请求响应TaskCompletionSource<T>.然而,TPL中的一个烦恼是,似乎不可能阻止同步延续.我会希望能够做的是两种:

  • 告诉a TaskCompletionSource<T>不应该允许呼叫者附加TaskContinuationOptions.ExecuteSynchronously,或
  • 使用池来设置结果(SetResult/ TrySetResult)以指定TaskContinuationOptions.ExecuteSynchronously应该忽略的方式

具体来说,我遇到的问题是传入的数据正在由专用的阅读器处理,如果调用者可以附加,TaskContinuationOptions.ExecuteSynchronously他们可以阻止阅读器(这不仅影响它们).以前,我通过一些hackery解决了这个问题,它检测是否存在任何延续,如果它们将完成推送到ThreadPool,那么如果调用者已经使工作队列饱和​​,则会产生重大影响,因为完成将不会被处理及时.如果他们使用Task.Wait()(或类似),他们将基本上陷入僵局.同样,这就是读者使用专用线程而不是使用工作者的原因.

所以; 在我尝试唠叨TPL团队之前:我错过了一个选项吗?

关键点:

  • 我不希望外部呼叫者能够劫持我的线程
  • 我不能使用它ThreadPool作为一个实现,因为它需要在池饱和时工作

以下示例生成输出(排序可能因时间而异):

Continuation on: Main thread
Press [return]
Continuation on: Thread pool
Run Code Online (Sandbox Code Playgroud)

问题在于随机调用者设法在"主线程"上获得延续.在实际代码中,这将打断主要读者; 坏事!

码:

using System;
using System.Threading;
using System.Threading.Tasks;

static class Program
{
    static void Identify()
    {
        var thread = Thread.CurrentThread;
        string name = thread.IsThreadPoolThread
            ? "Thread pool" : thread.Name;
        if (string.IsNullOrEmpty(name))
            name = …
Run Code Online (Sandbox Code Playgroud)

.net c# task task-parallel-library async-await

80
推荐指数
2
解决办法
7931
查看次数

递归和等待/异步关键字

我对await关键字的工作方式有一个脆弱的把握,我想稍微扩展一下我对它的理解.

仍然让我头疼的问题是使用递归.这是一个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestingAwaitOverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = TestAsync(0);
            System.Threading.Thread.Sleep(100000);
        }

        static async Task TestAsync(int count)
        {
            Console.WriteLine(count);
            await TestAsync(count + 1);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这显然是一个StackOverflowException.

我的理解是因为代码实际上是同步运行的,直到第一个异步操作,之后它返回一个Task包含异步操作信息的对象.在这种情况下,没有异步操作,因此它只是在最终得到Task返回的错误承诺下继续递归.

现在改变它只是一点点:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestingAwaitOverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = TestAsync(0);
            System.Threading.Thread.Sleep(100000); …
Run Code Online (Sandbox Code Playgroud)

c# recursion async-await

29
推荐指数
1
解决办法
6278
查看次数

"等待Task.Yield()"及其替代品

如果我需要推迟代码执行,直到UI线程消息循环的未来迭代之后,我可以这样做:

await Task.Factory.StartNew(
    () => {
        MessageBox.Show("Hello!");
    },
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)

这将类似于await Task.Yield(); MessageBox.Show("Hello!");,除了我有一个选项可以取消任务,如果我想.

在使用默认同步上下文的情况下,我可以类似地使用await Task.Run继续池线程.

事实上,我喜欢Task.Factory.StartNewTask.Run更多Task.Yield,因为他们都明确定义了延续代码的范围.

那么,在什么情况下await Task.Yield()实际上有用呢?

.net c# task-parallel-library async-await

21
推荐指数
3
解决办法
1万
查看次数

在Windows服务中的timer_elapsed事件处理程序中使用async等待

我在Windows服务中有一个计时器,并且在timer_Elapsed事件处理程序中调用了异步方法:

protected override void OnStart(string[] args)
{
     timer.Start();    
}  

private async void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    _timer.Stop();
    await DoSomething();          
    _timer.Start();
}
Run Code Online (Sandbox Code Playgroud)

上面的代码好吗?首先,我读过async void不是一个好主意.其次,为什么我需要timer_Elapsed方法首先异步?它不像我们将由多个调用者并行调用的已用事件处理程序.但是,如果我不使方法异步,那么我的逻辑将会中断,因为计时器将在DoSomething完成之前启动.

那么,正确的方法是使timer_Elapsed异步吗?

.net c# asynchronous windows-services async-await

9
推荐指数
1
解决办法
6122
查看次数

C#Parallel库,XmlReader,XmlWriter

我有一个用例,我需要:

  • 遍历Xml文档中的每个Input节点
  • 对每个输入执行时间密集的计算,并且
  • 将结果写入XML文件.

输入看起来像这样:

<Root>
  <Input>
    <Case>ABC123</Case>
    <State>MA</State>
    <Investor>Goldman</Investor>
  </Input>
  <Input>
    <Case>BCD234</Case>
    <State>CA</State>
    <Investor>Goldman</Investor>
  </Input>
</Root>
Run Code Online (Sandbox Code Playgroud)

和输出:

<Results>
  <Output>
    <Case>ABC123</Case>
    <State>MA</State>
    <Investor>Goldman</Investor>
    <Price>75.00</Price>
    <Product>Blah</Product>
  </Output>
  <Output>
    <Case>BCD234</Case>
    <State>CA</State>
    <Investor>Goldman</Investor>
    <Price>55.00</Price>
    <Product>Ack</Product>
  </Output>
</Results>
Run Code Online (Sandbox Code Playgroud)

我想并行运行计算; 典型的输入文件可能有50,000个输入节点,没有线程的总处理时间可能是90分钟.大约90%的处理时间花在步骤#2(计算)上.

我可以很容易地并行迭代XmlReader:

static IEnumerable<XElement> EnumerateAxis(XmlReader reader, string axis)
{
  reader.MoveToContent();
  while (reader.Read())
  {
    switch (reader.NodeType)
    {
      case XmlNodeType.Element:
        if (reader.Name == axis)
        {
          XElement el = XElement.ReadFrom(reader) as XElement;
          if (el != null)
            yield return el;
        }
        break;
    }
  }
} …
Run Code Online (Sandbox Code Playgroud)

c# parallel-processing multithreading xmlwriter

5
推荐指数
1
解决办法
2820
查看次数