C#Parallel.ForEach中线程上的Persist变量

C#Parallel.ForEach中线程上的Persist变量,c#,multithreading,parallel-processing,C#,Multithreading,Parallel Processing,我希望并行处理依赖于对象(状态)、的任务,该对象不是线程安全的,并且其构造非常耗时 出于这个原因,我一直在研究,但要么我做错了,要么我在寻找其他东西。这或多或少代表了我当前的实现: Parallel.ForEach(文件夹,配置,()=>newstate(),(源代码,循环状态,索引,线程状态)=>{ var content=File.ReadAllText(源);//读取文件 var result=threadState.doSomething(content);//做点什么 File.Wri

我希望并行处理依赖于对象(
状态
)、的任务,该对象不是线程安全的,并且其构造非常耗时

出于这个原因,我一直在研究,但要么我做错了,要么我在寻找其他东西。这或多或少代表了我当前的实现:

Parallel.ForEach(文件夹,配置,()=>newstate(),(源代码,循环状态,索引,线程状态)=>{
var content=File.ReadAllText(源);//读取文件
var result=threadState.doSomething(content);//做点什么
File.WriteAllText(outputFile,result);//写入输出
返回线程状态;
},(threadState)=>{});
但是,我在我的
状态
初始值设定项中添加了
控制台.WriteLine
,我发现循环的每次迭代都会调用
状态
构造函数,从而导致性能大幅度下降。我希望将一个线程中的
State
实例传递给同一线程上的后续迭代


我怎样才能做到这一点呢?

您有两个选择。最简单的方法是创建单个
状态
对象,并使用
锁同步对该对象的访问:

var state = new State();

Parallel.ForEach(folders, config, source =>
{
    var content = File.ReadAllText(source);
    string result;
    lock (state) { result = state.DoSomething(content); }
    File.WriteAllText(outputFile, result);
});
我假设这是不可行的,因为
DoSomething
方法非常耗时,同步它会破坏并行性

另一个选择是使用。此类提供数据的线程本地存储,因此创建的
State
对象的数量将等于
Parallel.ForEach
使用的线程数量

var threadLocalState = new ThreadLocal<State>(() => new State());

Parallel.ForEach(folders, config, source =>
{
    var content = File.ReadAllText(source);
    var result = threadLocalState.Value.DoSomething(content);
    File.WriteAllText(outputFile, result);
});
这样,实例化的
状态
对象的数量将等于最大并行度

唯一的问题是.NET平台中没有
ObjectPool
类(只有一个类),因此您必须找到一个。下面是一个简单的实现,它基于:

public类ObjectPool:IEnumerable其中T:new()
{
私有只读ConcurrentBag _bag=新ConcurrentBag();
私有只读功能工厂;
公共对象池(Func factory=null)=>\u factory=factory;
公屋租金()
{
如果(_bag.TryTake(out var obj))返回obj;
return _factory!=null?_factory():new T();
}
公共作废申报表(T obj)=>\u bag.Add(obj);
公共IEnumerator GetEnumerator()=>\u bag.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()=>this.GetEnumerator();
}

要么是我做错了
-你没有,只是。@GSerg似乎同时更新了,相关信息现在是正确的:“参与循环执行的每个任务调用一次localInit委托”(重点添加)
var statePool = new ObjectPool<State>(() => new State());

Parallel.ForEach(folders, config, source =>
{
    var state = statePool.Rent();
    var content = File.ReadAllText(source);
    var result = state.DoSomething(content);
    File.WriteAllText(outputFile, result);
    statePool.Return(state);
});
public class ObjectPool<T> : IEnumerable<T> where T : new()
{
    private readonly ConcurrentBag<T> _bag = new ConcurrentBag<T>();
    private readonly Func<T> _factory;

    public ObjectPool(Func<T> factory = null) => _factory = factory;

    public T Rent()
    {
        if (_bag.TryTake(out var obj)) return obj;
        return _factory != null ? _factory() : new T();
    }

    public void Return(T obj) => _bag.Add(obj);

    public IEnumerator<T> GetEnumerator() => _bag.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}