2017-10-20 35 views
-2

我想用真正的同步方法创建一个类库,所以我想避免实现一个只使用Task.Run来运行同步代码的假异步方法。如何实现真正的异步方法?

我已经看到,一个方法是这样:

public Task miMethodAsync() 
{ 
    TaskCompletionSource<bool> miTcs = new TaskCompletionSource<bool>(); 
    new Timer(_ => 
     { 
      for (Int64 i = 1; i < 10000000; i++) 
      { 
       //todo my long code 
      } 
      miTcs.SetResult(true); 
     }) 
     .Change(0, Timeout.Infinite); 

    return miTcs.Task; 
} 

该解决方案使用计时器返回的任务,然后在0毫秒后,它将运行在定时器中的代码。

此解决方案不会创建新任务,因此它不会占用线程表单线程池,因此可扩展性很好。但我认为这个解决方案,使用定时器来运行同步代码,这不是一个优雅的解决方案,所以我想知道我能够实现一个真正的异步方法。

因为这个解决方案还我可以有我的同步方法,只是实现这种方式ASYN方法:

public Task myMethodAsync() 
{ 
    TaskCompletionSource<bool> miTcs = new TaskCompletionSource<bool>(); 
    new Timer(_ => 
     { 
      myMethodSync(); 
      miTcs.SetResult(true); 
     }) 
     .Change(0, Timeout.Infinite); 

    return miTcs.Task; 
} 

但正如我的评论,我觉得这不是一个完美的解决方案,但实际上它似乎不是像我在Task.Run()方法内运行同步代码时那样的伪异步方法。

+0

如果计时器代码在同一个线程中运行(并且这是一个UI线程)并且运行时间很长,它仍然会冻结UI。如果;然而,计时器会创建一个新的线程,通过使用计时器隐藏这个线程,您获得了什么? –

+3

只要同步方法正在运行,这将用尽一个线程。无论这是活动线程,UI线程还是线程池线程,都取决于您正在使用的.NET库中名为Timer的六个类中的哪一个,以及哪个线程调用myMethodAsync()。 –

+1

你可以详细说明为什么你想在同步代码中创建一个'async'包装吗?假设你阅读引用的帖子[从你最后一个问题](https://stackoverflow.com/questions/46845005/is-it-really-a-bad-idea-to-use-threads-in-a-class-library )你知道这是一个坏主意。你是否正在履行“任务”返回界面?如果是,则返回'Task.FromResult'或'Task.CompletedTask',并再次让客户决定何时卸载该进程。没有更多的细节,你会得到以前的建议,即[**不要做**](https://stackoverflow.com/a/32642687/7339946)。 – JSteward

回答

1

这些将同步代码包装到伪async方法中的包装是没有用的。推荐的方法不是创建任何这样的包装器,而是让API用户自己执行Task.Run(SyncMethod)。

查看详细信息article