IObservable<Match> IObservableArray = new Regex("(.*):(.*)").Matches(file).OfType<Match>().ToList().ToObservable();
var query = IObservableArray.SelectMany(s => Observable.Start(() => {
//do stuff
}));
工作代码上面的说明:上面的代码使用带有Reactive的Observable来执行并发多线程系统,同时将s保留为匹配。
我的问题是,在开始执行//do stuff
之前似乎需要将所有内容加载到内存中,因为IObservableArray
是一个很大的匹配数组 - 这会占用大量内存导致它执行一个OutOfMemory例外。
我已经研究了一个多月了,我所能找到的就是.Buffer(),如果我把它放在.SelectMany()之前然后在s上匹配,我可以将1000匹配加载到内存中一段时间使整体记忆变得更好。
但是,因为我不得不求助于使用foreach一次遍历缓冲区中的所有1000个,所以它不是并发的 - 这意味着我基本上一个接一个地检查。
有没有办法在下面执行类似的代码,但是它有Concurrent / Multi-Threaded? (至少有150个并发运行,但不要将所有内容加载到内存中,目前使用1000个。)
是的,我尝试过使用thread.start等,使用它们会让它更早地触发完成的代码,因为从技术上来说它完成了,因为它已经完成了它被告知的所有内容使它们全部成为新线程
IObservable<Match> IObservableArray = new Regex("(.*):(.*)").Matches(file).OfType<Match>().ToList().ToObservable();
var query = IObservableArray.Buffer(1000).SelectMany(s => Observable.Start(() => {
//do stuff
}));
query.ObserveOn(ActiveForm).Subscribe(x =>
{
//do finish stuff
});
答案 0 :(得分:0)
您实际上并没有告诉Start()
使用哪个调度程序,这可能是您无法获得所需并发的原因。您可以将所需的调度程序指定为第二个参数:
var query = IObservableArray.Buffer(1000).SelectMany(s => Observable.Start(() => {
//do stuff
}, TaskPoolScheduler.Default));
如果您知道//do stuff
将花费超过500毫秒,我会考虑使用ThreadPoolScheduler
。任务池不会产生新线程,直到Task
阻塞线程至少500毫秒,所以如果你知道你将要做很多繁重的工作并需要大量的工作线程,您可以使用ThreadpoolScehduler.Instance
代替TaskPoolScheduler.Default
。
答案 1 :(得分:0)
对于此类工作,IEnumerable<T>
比 IObservable<T>
更匹配。可枚举是您可以按需展开的东西,并在您准备好处理它们时获取其值。相反,可观察对象是将其值强行推给您的东西,无论您是否能够处理负载。
有多种方法可以并行处理 IEnumerable<T>
,并具有特定的并行度。在提出任何建议之前,要问的第一个问题是您必须对每个 Match
做的事情是同步的还是异步的。对于同步工作,最常用的工具是 Parallel
类、PLINQ 和 TPL Dataflow 库。下面是一个 PLINQ 示例:
IEnumerable<Match> matches = RegexFindAllMatches(file, "(.*):(.*)");
Partitioner
.Create(matches, EnumerablePartitionerOptions.NoBuffering)
.AsParallel()
.WithDegreeOfParallelism(Environment.ProcessorCount)
.ForAll(match =>
{
// Do stuff
});
/// <summary>
/// Provides an enumerable whose elements are the successful matches found by
/// iteratively applying a regular expression pattern to the input string.
/// </summary>
public static IEnumerable<Match> RegexFindAllMatches(
string input, string pattern, RegexOptions options = RegexOptions.None,
TimeSpan matchTimeout = default)
{
if (matchTimeout == default) matchTimeout = Regex.InfiniteMatchTimeout;
var match = Regex.Match(input, pattern, options, matchTimeout);
while (match.Success)
{
yield return match;
match = match.NextMatch();
}
}
上面的实现避免了使用 Regex.Matches
方法,以及随后的 MatchCollection
类,因为虽然这个类在枚举期间懒惰地评估下一个 Match
,但它随后存储了每个找到的Match
在内部 ArrayList
(source code) 中。这可能会导致大量内存分配,与匹配总数成正比。
对于异步工作,Parallel
类和 PLINQ 不是好的选择(除非您愿意等待 .NET 6 Parallel.ForEachAsync
),但您仍然可以使用 TPL 数据流库。您还可以找到大量自定义选项 here 或 here。搜索 C# ForEachAsync 应该会显示更多选项。