我最近一直在学习F#,特别感兴趣的是它易于利用数据并行性.这个data |> Array.map |> Async.Parallel |> Async.RunSynchronously成语似乎很容易理解,直接使用并从中获得真正的价值.
那么为什么它async不是真正意图呢?Donald Syme本人表示,PLINQ和期货可能是更好的选择.我在这里读到的其他答案同意这一点以及推荐TPL.(PLINQ与上述内置函数似乎没什么不同,只要您使用F#Powerpack来获取PSeq函数.)
F#和函数式语言对此非常有意义,并且一些应用程序在async并行性方面取得了巨大成功.
那么为什么我不应该async用来执行并行数据流程呢?通过编写并行async代码而不是使用PLINQ或TPL,我将失去什么?
我试图在我的WPF应用程序中使我的UI更具响应性.我使用生成一个新线程
Task.Factory.StartNew( () => RecurseAndDeleteStart() );
Run Code Online (Sandbox Code Playgroud)
在该方法中,RecurseAndDeleteStart()我想要使用正在删除的文件更新UI中的标签.
如何实现这一目标?
比方说,我有三个任务,a,b,和c.所有这三个都保证在1到5秒之间的随机时间抛出异常.然后我写下面的代码:
await Task.WhenAny(a, b, c);
Run Code Online (Sandbox Code Playgroud)
这最终将从任何一个任务故障中抛出异常.由于这里没有try...catch,这个例外会冒泡到我的代码中的其他地方.
剩下的两个任务抛出异常会发生什么?是不是这些未被观察到的异常,这将导致整个过程被杀死?这是否意味着使用的唯一方法WhenAny是在try...catch块内,然后在继续之前以某种方式观察剩余的两个任务?
后续:我希望将答案同时应用于.NET 4.5 和 .NET 4.0以及Async Targeting Pack(尽管TaskEx.WhenAny在这种情况下明确使用).
我有2种C#WPF应用程序项目:
所有这些都应该产生2-10个长时间运行(天)的过程,这些过程可以被用户取消和重新启动.
我有兴趣遵循最佳设计实践.首先,现在,我有兴趣消除BackgroundWorker使用的歧义,但我希望,我的问题应该对其他异步模式有效.
我看到(矛盾)并发的观点
异步模式:
A).NET 4.5使它们过时了
"基于异步的异步编程方法几乎在所有情况下都优于现有方法.特别是,对于IO绑定操作,这种方法优于BackgroundWorker,因为代码更简单,您不必防范竞争条件.与Task.Run结合使用,异步编程优于 BackgroundWorker用于CPU绑定操作,因为异步编程将运行代码的协调细节与Task.Run传输到线程池的工作分开"
BackgroundWorker)在.NET 4.5中没有过时 我仍有疑问:
如果它们在.NET 4.5中已经过时,为什么它们在.NET 4.0中不会过时?
2A)我是否错误地理解.NET 4.0新功能在.NET 4.0中仍然"易于"实现/重现?
Task.Delay()没有按预期运行,或者说我不理解它应该做什么.我正试图Task在C#中解决问题,以及如何Thread在我的实现中替换s.
我想要做的是这样的事情:
我已经通过Threads很好地实现了,但是所有很酷的孩子都说我应该使用Task,而不要触摸Thread.
所以对于代码我有这个(忽略[Test]- 这只是一种方便的尝试方法)
[Test]
public void ChattyTask()
{
var chattyTask = new Task(ChattyWriter);
chattyTask.Start();
chattyTask.Wait();
}
public void ChattyWriter()
{
int count = 0;
while (true)
{
var message = String.Format("Chatty Writer number {0}", count);
Trace.WriteLine(message);
count++;
Task.Delay(1000);
if (count >= 20)
{
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,测试以毫秒为单位完成,而不是像我期望的那样在20秒内完成.如果我更换Task.Delay()用Thread.Sleep(),一切正常,我也得到了一次打印第二.我试过添加async和await进入ChattyWriter(),但不仅它没有添加1秒延迟,它只打印一行而不是20行.
我究竟做错了什么?
可能它有助于描述我正在做的事情:我的项目使用外部API(RESTful),在我请求执行某些任务之后,我需要轮询API以检查任务是否已完成.外部任务可以长时间运行:1-15分钟.所以我需要在检查完成之间有一些延迟.并且可能有许多不同的并发进程与多个外部任务一起执行.我明白,如果我Thread.Sleep()在轮询时使用,那么同样的其他进程Thread将被阻止,没有充分的理由.
我正在尝试在我的应用程序中记录/报告所有未处理的异常(错误报告解决方案).我遇到了一个总是未处理的情景.我想知道如何以未处理的方式捕获此错误.请注意,我今天早上做了很多研究并尝试了很多东西..是的,我已经看过这个,这个以及更多.我只是在寻找一种通用的解决方案来记录未处理的异常.
我在控制台测试应用程序主要方法中有以下代码:
Task.Factory.StartNew(TryExecute);
Run Code Online (Sandbox Code Playgroud)
要么
Task.Run((Action)TryExecute);
Run Code Online (Sandbox Code Playgroud)
以及以下方法:
private static void TryExecute() {
throw new Exception("I'm never caught");
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试在我的应用程序中连接到以下内容,但它们从未被调用过.
AppDomain.CurrentDomain.UnhandledException
TaskScheduler.UnobservedTaskException
Run Code Online (Sandbox Code Playgroud)
在我最初发现此错误的Wpf应用程序中,我也连接到这些事件,但它从未被调用过.
Dispatcher.UnhandledException
Application.Current.DispatcherUnhandledException
System.Windows.Forms.Application.ThreadException
Run Code Online (Sandbox Code Playgroud)
唯一被称为的处理程序是:
AppDomain.CurrentDomain.FirstChanceException
Run Code Online (Sandbox Code Playgroud)
但这不是一个有效的解决方案,因为我只想报告未捕获的异常(并非每个异常,因为在执行/解析任何catch块之前调用FirstChanceException.
我将如何构造下面的代码,以便调用异步方法?
Parallel.For(0, elevations.Count(), delegate(int i)
{
allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
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) 我喜欢新的System.Net.Http.HttpClient类.它有一个很好的简单API,它不会抛出正常的错误.但它只是异步.
我需要代码(深入服务器内)
foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);
Run Code Online (Sandbox Code Playgroud)
经典的顺序同步代码.我看到了几个类似的问题,但实际上从未真正说过"做这个".我在看
client.PostAsync.Wait()
Run Code Online (Sandbox Code Playgroud)
世界尖叫'不要这样做'.怎么样:
client.PostAsync.Result()
Run Code Online (Sandbox Code Playgroud)
这不只是伪装等待?
最后,我最终传入一个处理结果的lambda回调,然后唤醒显式等待EventWaitHandle的调用线程.很多管道.有没有更简单的东西或者我只是回到使用旧的http客户端
编辑:进一步阅读后,我怀疑这段代码与Wait和Result有相同的问题,它只是一个更长的死锁
编辑:我有MS PM最近向我确认有一个任务'可能需要> X ms(我忘了X)的任何API必须是异步',许多PM将此解释为'仅异步'(不清楚这是什么旨在).因此Document DB api只是异步.
我正在玩TPL,并试图通过并行读取和写入同一个词典来找出我可以做多么大的混乱.
所以我有这个代码:
private static void HowCouldARegularDicionaryDeadLock()
{
for (var i = 0; i < 20000; i++)
{
TryToReproduceProblem();
}
}
private static void TryToReproduceProblem()
{
try
{
var dictionary = new Dictionary<int, int>();
Enumerable.Range(0, 1000000)
.ToList()
.AsParallel()
.ForAll(n =>
{
if (!dictionary.ContainsKey(n))
{
dictionary[n] = n; //write
}
var readValue = dictionary[n]; //read
});
}
catch (AggregateException e)
{
e.Flatten()
.InnerExceptions.ToList()
.ForEach(i => Console.WriteLine(i.Message));
}
}
Run Code Online (Sandbox Code Playgroud)
它确实很乱,有很多异常抛出,大多数关于密钥不存在,一些关于索引超出数组的范围.
但运行应用程序一段时间后,它挂起,并且CPU百分比保持在25%,机器有8个核心.所以我假设2个线程满负荷运行.
然后我在上面运行了dottrace,得到了这个:
它符合我的猜测,两个线程以100%运行.
两者都运行Dictionary的FindEntry方法.
然后我用dottrace再次运行应用程序,这次结果略有不同:
这一次,一个线程正在运行FindEntry,另一个正在运行.
我的第一个直觉是它被锁定了,但后来我认为它不可能,只有一个共享资源,而且它没有被锁定.
那怎么解释呢?
ps:我不打算解决问题,可以通过使用ConcurrentDictionary或通过并行聚合来解决.我只是在寻找一个合理的解释.
.net c# parallel-processing multithreading task-parallel-library