标签: task-parallel-library

从WCF服务启动多个任务

我需要优化WCF服务......这是一件非常复杂的事情.这次我的问题与任务有关(Task Parallel Library,.NET 4.0).发生的事情是我在调用服务(使用Task.Factory.StartNew)时启动了几个任务,然后等待它们完成:

Task.WaitAll(task1, task2, task3, task4, task5, task6);
Run Code Online (Sandbox Code Playgroud)

好吧......我看到,不喜欢的是,在第一次通话时(有时前2-3次通话,如果一个接一个地快速完成),最后的任务比其他任务开始得晚(我正在寻找)在其他人开始后0.5秒开始的情况下).我试着打电话

ThreadPool.SetMinThreads(12*Environment.ProcessorCount, 20);
Run Code Online (Sandbox Code Playgroud)

在我的服务开始,但它似乎没有帮助.

这些任务都与数据库相关:我正在从多个数据库中读取数据,并且必须花费尽可能少的时间.

知道为什么最后一项任务花了这么长时间吗?有什么我可以做的吗?

或者,我应该直接使用线程池吗?事实上,在我看到的一个案例中,一个任务在最后一个任务开始之前已经结束 - 如果我重新使用该线程而不是等待创建新线程,我将节省0.2秒.但是,我不能肯定任务将最后总是这么快,所以我不能把两个请求在相同的任务.

[编辑]操作系统是Windows Server 2003,因此不应该有连接限制.此外,它托管在IIS中 - 我不知道我是应该创建常规线程还是使用线程池 - 这是首选版本?

[编辑]我也尝试过使用Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);- 它没有帮助,最后一项任务仍然比其他任务开始的时间晚了很多(大约半秒钟后).

[编辑] MSDN 1说:

在启动新的空闲线程之前,线程池具有内置延迟(.NET Framework 2.0版中的半秒).如果您的应用程序在短时间内定期启动许多任务,则空闲线程数量的少量增加可以显着提高吞吐量.将空闲线程数设置得太高会不必要地消耗系统资源.

但是,正如我所说的,我已经在调用SetMinThreads并且它没有帮助.

c# multithreading task-parallel-library

22
推荐指数
2
解决办法
2874
查看次数

在当前线程上执行任务

是否可以强制任务在当前线程上同步执行?

也就是说,通过例如传递一些参数StartNew()来制作这段代码是否可能:

Task.Factory.StartNew(() => ThisShouldBeExecutedSynchronously());
Run Code Online (Sandbox Code Playgroud)

表现得像这样:

ThisShouldBeExecutedSynchronously();
Run Code Online (Sandbox Code Playgroud)

背景:

我有一个名为的界面IThreads:

public interface IThreads
{
    Task<TRet> StartNew<TRet>(Func<TRet> func);
}
Run Code Online (Sandbox Code Playgroud)

我想有两个这样的实现,一个使用线程的普通:

public class Threads : IThreads
{
    public Task<TRet> StartNew<TRet>(Func<TRet> func)
    {
        return Task.Factory.StartNew(func);
    }
}
Run Code Online (Sandbox Code Playgroud)

并且不使用线程(在某些测试场景中使用):

public class NoThreading : IThreads
{
    public Task<TRet> StartNew<TRet>(Func<TRet> func)
    {
        // What do I write here?
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以让NoThreading版本调用func(),但我想返回一个Task<TRet>我可以执行操作的实例,例如ContinueWith().

c# task-parallel-library

22
推荐指数
4
解决办法
1万
查看次数

.NET 4中是否有Threadsafe Observable集合?

平台: WPF, .NET 4.0, C# 4.0

问题:在Mainwindow.xaml中,我有一个ListBox绑定到Customer集合,该集合当前是一个ObservableCollection <Customer>.

ObservableCollection<Customer> c = new ObservableCollection<Customer>();

此集合可以通过多个源进行更新,如FileSystem,WebService等.

为了允许并行加载Customers,我创建了一个帮助类

public class CustomerManager(ref ObsevableCollection<Customer> cust)

内部为每个客户源生成一个新任务(来自并行扩展库),并将新的Customer实例添加到客户集合对象(由ref传递给它的ctor).

问题是ObservableCollection <T>(或任何集合)不能在UI线程以外的调用中使用并遇到异常:

"NotSupportedException - 这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection."

我试过用了

System.Collections.Concurrent.ConcurrentBag<Customer>

集合但它没有实现INotifyCollectionChanged接口.因此我的WPF UI不会自动更新.

那么,是否有一个集合类可以实现属性/集合更改通知,还允许来自其他非UI线程的调用?

通过我最初的bing /谷歌搜索,没有提供开箱即用.

编辑:我创建了自己的集合,它继承自ConcurrentBag <Customer>,并且还实现了INotifyCollectionChanged接口.但令我惊讶的是,即使在单独的任务中调用它之后,WPF UI也会挂起,直到任务完成.是不应该并行执行任务而不阻止UI线程

提前感谢您的任何建议.

wpf .net-4.0 observablecollection task-parallel-library c#-4.0

21
推荐指数
2
解决办法
2万
查看次数

有没有办法使用ContinueWith任务启动任务?

我的代码:

var r = from x in new Task<int>(() => 1)
        from y in new Task<int>(() => x + 1) 
        select y;
r.ContinueWith(x => Console.WriteLine(x.Result)).Start();   
Run Code Online (Sandbox Code Playgroud)

要么

new Task<int>(() => 1)
    .ContinueWith(x => x.Result + 1)
    .ContinueWith(x => Console.WriteLine(x.Result))
    .Start();
Run Code Online (Sandbox Code Playgroud)

例外:

可能不会在继续任务上调用Start.

所以我需要开始第一项任务.有没有办法调用上一个任务Start方法来运行所有任务?

.net c# exception-handling task-parallel-library

21
推荐指数
1
解决办法
1万
查看次数

如何使WCF REST方法与任务并行库完全异步?

我试图使WCF REST方法完全异步(我不想阻止任何地方).基本上我有一个简单的服务,有3层:服务,业务逻辑和数据访问层.数据访问层正在访问数据库,可能需要几秒钟才能从该方法获得响应.

我不太清楚如何链接所有这些方法的工作.有人可以帮我完成我试图在下面写的样本吗?我不太了解WCF使用的模式,我没有找到关于这个主题的很多文档.

有人可以帮我完成以下示例吗?此外,如何测量服务能够处理比典型同步实现更多的负载?

using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Threading.Tasks;

namespace WcfRestService1
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = 
        AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1
    {
        private BusinessLogic bll = new BusinessLogic();

        // Synchronous version
        [WebGet(UriTemplate = "/sync")]
        public string GetSamples()
        {
            return bll.ComputeData();
        }

        // Asynchronous version - Begin
        [WebGet(UriTemplate = "/async")]
        [OperationContract(AsyncPattern = true)]
        public IAsyncResult BeginGetSampleAsync(AsyncCallback callback, 
            object state)
        {
            Task<string> t = bll.ComputeDataAsync();

            // What am I suppose to return …
Run Code Online (Sandbox Code Playgroud)

c# wcf asynchronous task-parallel-library

21
推荐指数
1
解决办法
6311
查看次数

等待非异步方法

我对C#中的整个await/async模式感到很困惑.

我有一个表单应用程序,我想调用一个需要20秒才能进行大量处理的方法.所以我想要await它.我认为正确的方法是将其标记为async Task但是这样做会产生警告,因为我不在其中的await任何地方使用它.

谷歌透露了一些关于返回的事情,TaskCompletionSource<T>但我没有返回类型,因为它是无效的.

如何使用此方法await

c# task-parallel-library

21
推荐指数
1
解决办法
1万
查看次数

"等待Task.Yield()"及其替代品

如果我需要推迟代码执行,直到UI线程消息循环的未来迭代之后,我可以这样做:

await Task.Factory.StartNew(
    () => {
        MessageBox.Show("Hello!");
    },
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)

这将类似于await Task.Yield(); MessageBox.Show("Hello!");,除了我有一个选项可以取消任务,如果我想.

在使用默认同步上下文的情况下,我可以类似地使用await Task.Run继续池线程.

事实上,我喜欢Task.Factory.StartNewTask.Run更多Task.Yield,因为他们都明确定义了延续代码的范围.

那么,在什么情况下await Task.Yield()实际上有用呢?

.net c# task-parallel-library async-await

21
推荐指数
3
解决办法
1万
查看次数

展平处理的AggregateExceptions

我遇到了几个我打电话的问题,但里面还有flatten另一个问题!这显然意味着它们正在链中传播并被卷入另一个链中.有没有办法递归展平所有内部AggregateExceptions?通常,我将使用句柄委托处理这些,但如果有另一个内部AggregateExceeption,则返回false.我没有妥善处理这些问题吗?AggregateExceptionAggregateExceptionAggregateException

编辑:既然我已经打电话展平,看来问题是,它没有被抓住,直到后来方式在调用堆栈.这是我正在调用Flatten()的代码.要在堆栈跟踪中使用,此方法称为WriteExceptionRecord(string,FileInfo):

do
{
    try
    {
        using (var stream = file.Open(FileMode.Append, FileAccess.Write, FileShare.None))
        {
            using (StreamWriter writer = new StreamWriter(stream))
            {
                await writer.WriteLineAsync(data);
            }
        }
    }
    catch (AggregateException ex)
    {
        ex.Flatten().Handle((x) =>
        {
            if (x is IOException)
            {
                retryNeeded = true;
                retryLeft--;
                Thread.Sleep(500);
                return true;
            }

            logger.ErrorException("Could not write to exception file: " + data, ex);
            return false;
        });
    }
}
while (retryNeeded && retryLeft > 0);
Run Code Online (Sandbox Code Playgroud)

但是,堆栈跟踪显示它没有被捕获.相反,它会在调用堆栈之后被捕获.以下是出于安全原因删除了一些识别信息的跟踪:

System.AggregateException: One or more errors occurred. ---> …
Run Code Online (Sandbox Code Playgroud)

c# exception task-parallel-library aggregateexception

21
推荐指数
3
解决办法
2万
查看次数

捕获TaskCanceledException并检查Task.Canceled是个好主意?

我团队中有些人非常喜欢使用异步编码Task.有时他们喜欢使用CancellationToken参数.

我不确定的是我们作为一个团队是否应该使用这种代码风格(A):

async Task<someObject> DoStuff(CancellationToken t)
{
    while (!t.IsCanceled)
    {
        try {
            Task.Delay(5000, t);
        }
        catch (AggregateException e) // or is it TaskCanceledException or OperationCanceledException? I don't know? :)
        {
        }
        // poll something, return someObject, or null
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

这显然意味着调用者可能必须自己检查取消令牌以确定是否继续处理,并且他们可能必须处理null retVals:

var retVal = await DoStuff(token);
if (token.IsCanceled) { ... }
Run Code Online (Sandbox Code Playgroud)

但是,如果我们采用依赖于TaskCanceledException的第二种代码(B):

async Task<someObject> DoStuff(CancellationToken t)
{
    while(true)
    {
        Task.Delay(5000, t);
        // poll something, return someObject, or null
    }
}
Run Code Online (Sandbox Code Playgroud)

实现代码肯定更简单 - 调用者可以选择是否处理异常,但是我不禁担心调用者可能会 …

.net c# task task-parallel-library cancellation-token

21
推荐指数
1
解决办法
7675
查看次数

TaskContinuationOptions.RunContinuations异步和Stack Dives

这篇博文中,Stephan Toub描述了一个将包含在.NET 4.6中的新功能,它为被调用的TaskCreationOptions和TaskContinuationOptions枚举增加了另一个值RunContinuationsAsynchronously.

他解释说:

"我谈到了在TaskCompletionSource上调用{Try} Set*方法的分支,TaskCompletionSource的Task的任何同步延续都可以作为调用的一部分同步运行.如果我们在这里调用SetResult同时持有锁,那么同步延续关闭那个任务将在持有锁的同时运行,这可能会导致非常真实的问题.所以,在持有锁时我们抓住TaskCompletionSource来完成,但我们还没有完成它,延迟这样做直到锁定已被释放"

并给出以下示例来演示:

private SemaphoreSlim _gate = new SemaphoreSlim(1, 1);
private async Task WorkAsync()
{
    await _gate.WaitAsync().ConfigureAwait(false);
    try
    {
        // work here
    }
    finally { _gate.Release(); }
}
Run Code Online (Sandbox Code Playgroud)

现在假设你有很多对WorkAsync的调用:

await Task.WhenAll(from i in Enumerable.Range(0, 10000) select WorkAsync());
Run Code Online (Sandbox Code Playgroud)

我们刚刚创建了10,000个对WorkAsync的调用,这些调用将在信号量上进行适当的序列化.其中一个任务将进入关键区域,其他任务将在WaitAsync调用上排队,SemaphoreSlim内部有效地将任务调用完成,当有人调用Release时.如果Release同步完成了Task,那么当第一个任务调用Release时,它将同步开始执行第二个任务,当它调用Release时,它将同步开始执行第三个任务,依此类推.如果上面代码的"// work here"部分没有包含任何等待产生的东西,那么我们可能会在这里堆叠潜水并最终可能导致堆栈爆炸.

我很难掌握他谈论同步执行延续的部分.

怎么可能导致堆栈潜水?更重要的是RunContinuationsAsynchronously,为了解决这个问题,有效的做法是什么?

.net c# task-parallel-library async-await .net-4.6

21
推荐指数
2
解决办法
4214
查看次数