我正在使用异步/等待和Task很多,但从来没有使用过Task.Yield(),说实话,即使有所有的解释,我不明白为什么我需要这种方法.
有人可以在Yield()需要的地方举个好例子吗?
我一直在阅读有关Task.Yield,而且作为一名JavaScript开发,我可以告诉大家,就是它的工作是 完全相同一样setTimeout(function (){...},0);在让主单线程处理又名其他的东西方面:
"不要把所有的力量从时间上释放出来 - 所以其他人也会有一些......"
在js中,它特别适用于长循环.(不要让浏览器冻结......)
但我在这里看到了这个例子:
public static async Task < int > FindSeriesSum(int i1)
{
int sum = 0;
for (int i = 0; i < i1; i++)
{
sum += i;
if (i % 1000 == 0) ( after a bulk , release power to main thread)
await Task.Yield();
}
return sum;
}
Run Code Online (Sandbox Code Playgroud)
作为JS程序员,我可以理解他们在这里做了什么.
但作为一名C#程序员,我问自己:为什么不为它开一个任务呢?
public static async Task < int > FindSeriesSum(int i1)
{
//do something.... …Run Code Online (Sandbox Code Playgroud) 阅读太久了.使用Task.ConfigureAwait(continueOnCapturedContext: false)可能会引入冗余线程切换.我正在寻找一致的解决方案.
长版.隐藏的主要设计目标ConfigureAwait(false)是在可能的情况下减少冗余的SynchronizationContext.Post延续回调await.这通常意味着更少的线程切换和更少的UI线程工作.但是,它并不总是如何运作.
例如,有一个实现SomeAsyncApiAPI的第三方库.请注意ConfigureAwait(false),由于某些原因,此库中的任何位置都不使用:
// some library, SomeClass class
public static async Task<int> SomeAsyncApi()
{
TaskExt.Log("X1");
// await Task.Delay(1000) without ConfigureAwait(false);
// WithCompletionLog only shows the actual Task.Delay completion thread
// and doesn't change the awaiter behavior
await Task.Delay(1000).WithCompletionLog(step: "X1.5");
TaskExt.Log("X2");
return 42;
}
// logging helpers
public static partial class TaskExt
{
public static void Log(string step)
{
Debug.WriteLine(new { step, thread = Environment.CurrentManagedThreadId }); …Run Code Online (Sandbox Code Playgroud) 我今天尝试使用SwitchTo方法切换到GUI线程,并发现我解除它的示例不起作用,仅仅是因为该方法不存在.
然后我在这里发现了这个模糊:
我们摆脱它的原因是因为它太危险了.另一种方法是在TaskEx.Run中捆绑你的代码......
我的问题很简单:为什么它很危险?使用它会带来哪些特定的危险?
请注意,我确实阅读了该帖子的其余部分,因此我确实理解这里存在技术限制.我的问题仍然是,如果我意识到这一点,为什么它很危险?
我正在考虑重新实现帮助方法来给我指定的功能,但如果有一些根本性的破坏,除了有人认为它是危险的,我不会这样做.
具体来说,非常天真,这是我如何考虑实现所需的方法:
public static class ContextSwitcher
{
public static ThreadPoolContextSwitcher SwitchToThreadPool()
{
return new ThreadPoolContextSwitcher();
}
public static SynchronizationContextSwitcher SwitchTo(this SynchronizationContext synchronizationContext)
{
return new SynchronizationContextSwitcher(synchronizationContext);
}
}
public class SynchronizationContextSwitcher : INotifyCompletion
{
private readonly SynchronizationContext _SynchronizationContext;
public SynchronizationContextSwitcher(SynchronizationContext synchronizationContext)
{
_SynchronizationContext = synchronizationContext;
}
public SynchronizationContextSwitcher GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
return false;
}
}
public void OnCompleted(Action action) …Run Code Online (Sandbox Code Playgroud) 这是一个WinForms代码:
async void Form1_Load(object sender, EventArgs e)
{
// on the UI thread
Debug.WriteLine(new { where = "before",
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread });
var tcs = new TaskCompletionSource<bool>();
this.BeginInvoke(new MethodInvoker(() => tcs.SetResult(true)));
await tcs.Task.ContinueWith(t => {
// still on the UI thread
Debug.WriteLine(new { where = "ContinueWith",
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread });
}, TaskContinuationOptions.ExecuteSynchronously).ConfigureAwait(false);
// on a pool thread
Debug.WriteLine(new { where = "after",
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread });
}
Run Code Online (Sandbox Code Playgroud)
输出:
{ where = before, ManagedThreadId = 10, IsThreadPoolThread = False }
{ where = ContinueWith, … 我有一个MVC应用程序,我覆盖我的基本控制器的OnActionExecuting()方法来设置我的线程文化:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
var langCode = GetLangCode();
Thread.CurrentThread.CurrentUICulture = new CultureInfo(langCode);
Thread.CurrentThread.CurrentCulture = new CultureInfo(langCode);
}
Run Code Online (Sandbox Code Playgroud)
当我开始异步编程时,如果我们将我们修改过的文化返回到线程池,并且在异步任务完成时调度新线程,我很好奇文化是如何持久化的?我应该知道的任何陷阱?
我需要通过SignalR集线器调用发送电子邮件.我不希望send同步执行,因为我不想绑定WebSocket连接,但是如果可能的话,我希望通知调用者是否有任何错误.我以为我可以在集线器中使用这样的东西(减去错误处理和我希望它做的所有其他事情):
public class MyHub : Hub {
public async Task DoSomething() {
var client = new SmtpClient();
var message = new MailMessage(/* setup message here */);
await client.SendMailAsync(message);
}
}
Run Code Online (Sandbox Code Playgroud)
但很快发现它不起作用; client.SendMailAsync调用抛出这个:
System.InvalidOperationException:此时无法启动异步操作.异步操作只能在异步处理程序或模块中启动,或者在页面生命周期中的某些事件中启动.
进一步的调查和阅读告诉我,SmtpClient.SendMailAsync是围绕EAP方法的TAP包装器,而SignalR不允许这样做.
我的问题是,有没有简单的方法直接从集线器方法发送电子邮件?
或者我唯一的选择是将电子邮件发送到其他地方吗?(例如,让集线器队列成为服务总线消息,然后一个独立服务可以处理这些消息并发送电子邮件[虽然我也有更多的工作来实现结果通知回集中的客户端];或者让集线器向发送电子邮件的Web服务发出HTTP请求.
我想我不懂东西.我原本以为Task.Yield()强制为一个任务启动一个新的线程/上下文,但是在重新阅读这个答案时,它似乎只是强制该方法是异步的.它仍然是在相同的背景下.
什么是正确的方法 - 在asp.net进程中 - 并行创建和运行多个任务而不会导致死锁?
换句话说,假设我有以下方法:
async Task createFileFromLongRunningComputation(int input) {
//many levels of async code
}
Run Code Online (Sandbox Code Playgroud)
当某个POST路由被命中时,我想同时启动上述方法3次,立即返回,但是当完成所有这三个时都要记录.
我想我需要把这样的东西放进我的行动中
public IHttpAction Post() {
Task.WhenAll(
createFileFromLongRunningComputation(1),
createFileFromLongRunningComputation(2),
createFileFromLongRunningComputation(3)
).ContinueWith((Task t) =>
logger.Log("Computation completed")
).ConfigureAwait(false);
return Ok();
Run Code Online (Sandbox Code Playgroud)
}
需要了解什么createFileFromLongRunningComputation?我原以为Task.Yield是正确的,但显然不是.
async-await ×8
c# ×8
.net ×2
.net-4.5 ×1
asp.net ×1
asp.net-mvc ×1
async-ctp ×1
asynchronous ×1
c#-5.0 ×1
email ×1
signalr ×1
smtpclient ×1