我一直在阅读有关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) TL; DR:运行任务中的死锁StaTaskScheduler.长版:
我使用的是StaTaskScheduler从ParallelExtensionsExtras中通过平行小组,举办由第三方提供的一些遗留STA COM对象.StaTaskScheduler实现细节的描述如下:
好消息是TPL的实现能够在MTA或STA线程上运行,并考虑到底层API的相关差异,如WaitHandle.WaitAll(当方法提供多个等待句柄时,它只支持MTA线程).
我认为这意味着TPL的阻塞部分将使用等待API来提供消息,例如CoWaitForMultipleHandles,以避免在STA线程上调用时出现死锁情况.
在我的情况下,我相信发生以下情况:进程内STA COM对象A调用进程外对象B,然后期望从B通过回调作为传出调用的一部分.
以简化形式:
var result = await Task.Factory.StartNew(() =>
{
// in-proc object A
var a = new A();
// out-of-proc object B
var b = new B();
// A calls B and B calls back A during the Method call
return a.Method(b);
}, CancellationToken.None, TaskCreationOptions.None, staTaskScheduler);
Run Code Online (Sandbox Code Playgroud)
问题是,a.Method(b)永远不会回来.据我所知,这是因为内部阻塞等待BlockingCollection<Task>不会引发消息,因此我对引用语句的假设可能是错误的.
EDITED相同的代码工作测试WinForms应用程序的UI线程上执行时(即,提供TaskScheduler.FromCurrentSynchronizationContext()的,而不是staTaskScheduler到Task.Factory.StartNew).
解决这个问题的正确方法是什么?我应该实现一个自定义同步上下文,它将显式地使用消息CoWaitForMultipleHandles …
我今天尝试使用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) 我有一台通过TCP LAN与50个或更多设备进行通信的服务器。每个套接字读取消息循环都有一个Task.Run。
我将每条消息的到达缓冲到一个阻塞队列中,在每个阻塞队列中都有一个使用BlockingCollection.Take()的Task.Run。
所以像(半伪代码):
套接字读取任务
Task.Run(() =>
{
while (notCancelled)
{
element = ReadXml();
switch (element)
{
case messageheader:
MessageBlockingQueue.Add(deserialze<messageType>());
...
}
}
});
Run Code Online (Sandbox Code Playgroud)
消息缓冲区任务
Task.Run(() =>
{
while (notCancelled)
{
Process(MessageQueue.Take());
}
});
Run Code Online (Sandbox Code Playgroud)
因此,这将使50多个读取任务和50多个任务在自己的缓冲区中阻塞。
我这样做是为了避免阻塞阅读循环,并允许程序更公平地分配对消息的处理时间,所以我相信。
这是一种低效的处理方式吗?有什么更好的方法?
c# parallel-processing performance networking multithreading
c# ×4
async-await ×3
.net ×1
.net-4.5 ×1
async-ctp ×1
asynchronous ×1
c#-5.0 ×1
com ×1
networking ×1
performance ×1