共享对象上下文任务

时间:2017-03-24 08:43:59

标签: c# multithreading thread-safety task-parallel-library .net-4.5.2

我有一个列表lstSubscriptionRequests,其中我正在异步处理某些异步项目。然后在处理完所有项目之后,我必须返回更新的列表项目。我目前的实现就像

List<SubscriptionRequest> lstSubscriptionRequests = FromSomeResource();

 var tsk = new List<Task>();
                foreach (var oTsk in lstSubscriptionRequests.Select(objSubscriptionRequest => new Task(
                    () => ProcessSubscriptionForASingleRecord(objSubscriptionRequest))))
                {
                    oTsk.Start();
                    lock (tsk)
                    {
                        tsk.Add(oTsk);
                    }
                }
                Task.WaitAll(tsk.ToArray());

在完成所有任务后,某些项目看起来没有更新。 请让我知道我需要的更正

1 个答案:

答案 0 :(得分:2)

你可以更轻松地完成这项工作。请注意,通常不需要或不建议使用Task构造函数,也可能难以跟踪或调试特定对象的状态。返回表示所需状态的新对象将允许您强制执行最小有效状态。以下代码将处理您的所有项目,并将完成的项目返回到您的客户端代码。

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Processing {
    public class MyProcessor {

        public async Task<IEnumerable<Subscription>> ProcessSubscriptionRequestsAsync(IEnumerable<SubscriptionRequest> subscriptionRequests) {
            var subscriptionProcessingTasks = subscriptionRequests.Select(request => ProcessSubscriptionForASingleRecord(request)).ToArray();
            return await Task.WhenAll(subscriptionProcessingTasks);
        }

        public async Task<Subscription> ProcessSubscriptionForASingleRecord(SubscriptionRequest request) {
            //process the request
            try {
                var subscription = await Context.ProcessRequest(request);
                return subscription;
            } catch {
                //something went wrong with the request
            }
        }
    }

    public class SubscriptionRequest {
        //A subcription request
    }

    public class Subscription {
        //A completed subscription request
    }
}

<强>更新

  

如果您可以排除新的类订阅并在答案中添加解决方案,这可能有所帮助。我会试一试

希望简化的前后视图将更容易集成。主要区别在于将Parallel.ForEach替换为Select以创建您的任务集合,而无需锁定每个SubscriptionRequest的任务列表,同时还假设Task并行通常不是必需的,因为每个都将异步执行,您只能获得所有等待的点,而不是完成。接下来,允许每个任务开始,并在await Task.WhenAll(tasks)等待所有任务。确定每个SubscriptionRequest经历的处理类型非常重要。为了举例,我假设每个请求都以某种方式链接到数据库访问,即存储请求,更新各种类型的用户配置文件等。

public class OriginalSynchronous {

    public void ProcessSubscriptionRequest() {
        List<SubscriptionRequest> lstSubscriptionRequests = FromSomeResource();

        List<Task> tsk = new List<Task>();
        Parallel.ForEach(lstSubscriptionRequests, objSubscriptionRequest => {
            var oTsk =
                new Task(
                    () => ProcessSubscriptionForASingleRecord(objSubscriptionRequest));// update some properties after processing SubscriptionRequest
            oTsk.Start();
            lock (tsk) {
                tsk.Add(oTsk);
            }

        });
        Task.WaitAll(tsk.ToArray());
    }

    private void ProcessSubscriptionForASingleRecord(SubscriptionRequest request) {
        //modify SubscriptionRequest
    }
}

public class ModifiedAsync {

    public async Task ProcessSubscriptionRequest() {
        var subscriptionRequests = await FromSomeResourceAsync();
        var tasks = subscriptionRequests.Select(request => {
            return ProcessSubscriptionForASingleRecord(request);
        }).ToArray();
        await Task.WhenAll(tasks);
    }

    public async Task ProcessSubscriptionForASingleRecord(SubscriptionRequest request) {
        //modify SubscriptionRequest
    }
}