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();
}