.NET 4.5中 有Task.Delay
我怎么能在.NET 4.0中做同样的事情?
.net c# parallel-processing multithreading task-parallel-library
至少从.NET 4.0发布以来,微软似乎已经付出了很多努力来支持并行和异步编程,而且似乎已经出现了很多API和库.特别是最近随处可见的以下花哨的名字:
现在它们似乎都是微软的产品,它们似乎都针对.NET的异步或并行编程场景.但目前尚不清楚它们实际上是什么以及它们如何相互关联.实际上有些可能是同一件事.
简而言之,任何人都可以直接记录什么是什么?
parallel-extensions plinq task-parallel-library system.reactive
我有三种方法可以做一些数字运算,如下所示
results.LeftFront.CalcAi();
results.RightFront.CalcAi();
results.RearSuspension.CalcAi(geom, vehDef.Geometry.LTa.TaStiffness, vehDef.Geometry.RTa.TaStiffness);
Run Code Online (Sandbox Code Playgroud)
每个函数彼此独立,并且可以并行计算而没有死锁.
在没有包含方法完成之前,并行计算这些内容的最简单方法是什么?
将使用回调的"经典"异步方法转换/包装到返回(等待)任务的东西的最佳方法是什么?
例如,给定以下方法:
public void GetStringFromUrl(string url, Action<string> onCompleted);
Run Code Online (Sandbox Code Playgroud)
我知道将它包装成返回任务的方法的唯一方法是:
public Task<string> GetStringFromUrl(string url)
{
var t = new TaskCompletionSource<string>();
GetStringFromUrl(url, s => t.TrySetResult(s));
return t.Task;
}
Run Code Online (Sandbox Code Playgroud)
这是实现这一目标的唯一方法吗?
有没有办法在任务本身中包含对GetStringFromUrl(url,callback)的调用(即调用本身将在任务内运行而不是同步)
我正在尝试将数据库中存储图像的数据库迁移到指向硬盘驱动器上的文件的数据库中的记录.我试图使用此方法来查询数据Parallel.ForEach以加快进程.
但是,我注意到我得到了一个OutOfMemory例外.我知道Parallel.ForEach会查询一批枚举,以减少开销的成本,如果有一个用于间隔查询(如果您一次执行一堆查询而不是间隔它们,您的源将更有可能将下一条记录缓存在内存中)出).问题是由于我返回的记录之一是1-4Mb字节数组,缓存导致整个地址空间用完(程序必须在x86模式下运行,因为目标平台将是32位机)
是否有任何方法可以禁用缓存或使TPL更小?
这是一个显示问题的示例程序.这必须在x86模式下编译,以显示问题,如果它在你的机器上花费很长时间或者没有发生,从而增加了阵列的大小(我发现1 << 20我的机器上大约需要30秒,4 << 20几乎是瞬间的)
class Program
{
static void Main(string[] args)
{
Parallel.ForEach(CreateData(), (data) =>
{
data[0] = 1;
});
}
static IEnumerable<byte[]> CreateData()
{
while (true)
{
yield return new byte[1 << 20]; //1Mb array
}
}
}
Run Code Online (Sandbox Code Playgroud) 想想这个,
Task task = new Task (async () =>{
await TaskEx.Delay(1000);
});
task.Start();
task.Wait();
Run Code Online (Sandbox Code Playgroud)
调用task.Wait()不等待任务完成,下一行立即执行,但如果我将async lambda表达式包装到方法调用中,代码将按预期工作.
private static async Task AwaitableMethod()
{
await TaskEx.Delay(1000);
}
Run Code Online (Sandbox Code Playgroud)
然后(根据svick的评论更新)
await AwaitableMethod();
Run Code Online (Sandbox Code Playgroud) 这是我的代码,但我不明白SemaphoreSlim在做什么.
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
List<Task> trackedTasks = new List<Task>();
while (DoMore())
{
await ss.WaitAsync();
trackedTasks.Add(Task.Run(() =>
{
DoPollingThenWorkAsync();
ss.Release();
}));
}
await Task.WhenAll(trackedTasks);
}
void DoPollingThenWorkAsync()
{
var msg = Poll();
if (msg != null)
{
Thread.Sleep(2000); // process the long running CPU-bound job
}
}
Run Code Online (Sandbox Code Playgroud)
等待ss.WaitAsync(); & ss.Release();做什么?
我想如果我一次运行50个线程然后编写代码SemaphoreSlim ss = new SemaphoreSlim(10);那么它将被迫在时间运行10个活动线程.
当10个线程中的一个完成然后另一个线程将启动....如果我不对,那么请帮助我理解样本情况.
为什么需要等待使用ss.WaitAsync();?怎么ss.WaitAsync();办?
我正在更新具有在.NET 3.5中构建的API表面的库.因此,所有方法都是同步的.我无法更改API(即,将返回值转换为Task),因为这将要求所有调用者都更改.所以我留下了如何以同步方式最好地调用异步方法.这是在ASP.NET 4,ASP.NET Core和.NET/.NET Core控制台应用程序的上下文中.
我可能不够清楚 - 情况是我现有的代码不是异步识别的,我想使用新的库,如System.Net.Http和仅支持异步方法的AWS SDK.所以我需要缩小差距,并且能够拥有可以同步调用的代码,然后可以在其他地方调用异步方法.
我已经做了很多阅读,并且有很多次这已经被问及并回答了.
问题是大多数答案都不同!我见过的最常见的方法是使用.Result,但这可能会死锁.我已经尝试了以下所有内容,并且它们可以工作,但我不确定哪种方法可以避免死锁,具有良好的性能,并且可以很好地运行运行时(在尊重任务调度程序,任务创建选项等方面) ).有明确的答案吗?什么是最好的方法?
private static T taskSyncRunner<T>(Func<Task<T>> task)
{
T result;
// approach 1
result = Task.Run(async () => await task()).ConfigureAwait(false).GetAwaiter().GetResult();
// approach 2
result = Task.Run(task).ConfigureAwait(false).GetAwaiter().GetResult();
// approach 3
result = task().ConfigureAwait(false).GetAwaiter().GetResult();
// approach 4
result = Task.Run(task).Result;
// approach 5
result = Task.Run(task).GetAwaiter().GetResult();
// approach 6
var t = task();
t.RunSynchronously();
result = t.Result;
// approach 7
var t1 = task();
Task.WaitAll(t1); …Run Code Online (Sandbox Code Playgroud) c# asp.net multithreading asynchronous task-parallel-library
我没有看到C#(和VB)的新异步功能和.NET 4.0的任务并行库之间存在差异.举个例子来说,埃里克利珀的代码从这里:
async void ArchiveDocuments(List<Url> urls) {
Task archive = null;
for(int i = 0; i < urls.Count; ++i) {
var document = await FetchAsync(urls[i]);
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
}
Run Code Online (Sandbox Code Playgroud)
似乎该await关键字有两个不同的用途.第一个出现(FetchAsync)似乎意味着,"如果稍后在方法中使用此值并且其任务未完成,请等到它完成后再继续." 第二个实例(archive)似乎意味着,"如果此任务尚未完成,请立即等待直到完成." 如果我错了,请纠正我.
难道不能像这样容易写吗?
void ArchiveDocuments(List<Url> urls) {
for(int i = 0; i < urls.Count; ++i) {
var document = FetchAsync(urls[i]); // removed await
if (archive != null) …Run Code Online (Sandbox Code Playgroud) 任务并行库很棒,在过去的几个月里我经常使用它.但是,有一些事情让我感到困扰:事实TaskScheduler.Current是默认的任务调度程序,而不是TaskScheduler.Default.这在文档和样本中乍一看绝对不是很明显.
Current可以导致细微的错误,因为它的行为正在改变,这取决于你是否在另一个任务中.哪个不容易确定.
假设我正在编写异步方法库,使用基于事件的标准异步模式来表示原始同步上下文的完成,这与XxxAsync方法在.NET Framework中完全相同(例如DownloadFileAsync).我决定使用任务并行库来实现,因为使用以下代码实现此行为非常容易:
public class MyLibrary
{
public event EventHandler SomeOperationCompleted;
private void OnSomeOperationCompleted()
{
SomeOperationCompleted?.Invoke(this, EventArgs.Empty);
}
public void DoSomeOperationAsync()
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // simulate a long operation
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(t =>
{
OnSomeOperationCompleted(); // trigger the event
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切运作良好.现在,让我们在WPF或WinForms应用程序中单击按钮调用此库:
private void Button_OnClick(object sender, EventArgs args)
{
var myLibrary = new MyLibrary();
myLibrary.SomeOperationCompleted += (s, e) => DoSomethingElse();
myLibrary.DoSomeOperationAsync(); // call that triggers the …Run Code Online (Sandbox Code Playgroud) .net c# conceptual synchronizationcontext task-parallel-library
c# ×9
.net ×2
async-await ×2
asynchronous ×2
c#-5.0 ×2
asp.net ×1
async-ctp ×1
conceptual ×1
large-data ×1
plinq ×1
semaphore ×1