我正在使用C#,我有一个枚举器,我按顺序读取枚举器中的数据。
这是第三方库对象,不支持Parallel.Foreach
while(enumerator.Next())
{
var item = enumerator.Read();
ProcessItem(item);
}
ProcessItem(Item item)
{
// Is lock required here
if(item.prop == "somevalue")
this._list.Add(item);
}
我想在阅读内容时在这里实现多线程。
while(enumerator.Next())
{
// This code should run in a multi-threaded way
var item = enumerator.Read();
// ProcessItem method puts these items on a class level list property
// Is there any Lock required?
ProcessItem(item);
}
我是多线程的新手。请分享满足上述要求的任何代码样本。
答案 0 :(得分:2)
是的,需要一些锁定。你可以使用锁或使用并发集合类型来实现它。
使用lock
:
ProcessItem(Item item)
{
if(item.prop == "somevalue")
{
lock(_list)
{
_list.Add(item);
}
}
}
编辑:根据您提供的详细信息,您可以使用自己的枚举器从外部lib中包装enumerator
,以便您可以使用Parallel.ForEach
:
我们假设您获得的枚举器类似于MockEnumerator
,我们将其包装在普通的IEnumerator中,并且IEnumerable使我们能够使用Parallel.ForEach
并行读取。
class Program
{
class Item
{
public int SomeProperty { get; }
public Item(int prop)
{
SomeProperty = prop;
}
}
class MockEnumerator
{
private Item[] _items = new Item[] { new Item(1), new Item(2) };
private int _position = 0;
public bool Next()
{
return _position++ < _items.Length;
}
public Item Read()
{
return _items[_position];
}
}
class EnumeratorWrapper : IEnumerator<Item>, IEnumerable<Item>
{
private readonly MockEnumerator _enumerator;
public EnumeratorWrapper(MockEnumerator enumerator)
{
this._enumerator = enumerator;
}
public Item Current => _enumerator.Read();
object IEnumerator.Current => Current;
public void Dispose()
{
}
public IEnumerator<Item> GetEnumerator()
{
throw new NotImplementedException();
}
public bool MoveNext()
{
return _enumerator.Next();
}
public void Reset()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return this;
}
}
private static List<Item> _list = new List<Item>();
static void Main(string[] args)
{
var enumerator = new EnumeratorWrapper(new MockEnumerator());
Parallel.ForEach(enumerator, item =>
{
if (item.SomeProperty == 1)//someval
{
lock (_list)
{
_list.Add(item);
}
}
});
}
}
答案 1 :(得分:1)
这是基于任务的并行化的一个很好的例子。项目的每个处理对应于任务。因此,您可以将循环更改为以下内容:
var tasks = new List<Task<int>>();
while(enumerator.MoveNext())
{
var item = enumerator.Current;
Task<int> task = new Task<int>(() => ProcessItem(item));
task.Start();
tasks.Add(task);
}
foreach(Task<int> task in tasks)
{
int i = task.Result;
classList.Add(i);
}
请注意,classList
上的同步是通过首先在while循环中生成所有任务,然后在foreach循环中合并结果来隐式给出的。通过Result
访问 string[] libraryCssList = new string[]
{
"~/Content/css1.css",
"~/Content/css2.css",
}; // works fine
// error begins:
bundles.UseCdn = true;
var fontRokkittCss = "https://fonts.googleapis.com/css?family=Rokkitt:200,300,400,700";
bundles.Add(new StyleBundle("~/Content/libraryCss")
.Include(libraryCss)
.Include(fontRokkittCss));
来明确同步。