gpt4 book ai didi

c# - C# 中是否存在异步正则表达式,它们对我的情况有帮助吗?

转载 作者:太空狗 更新时间:2023-10-30 00:31:27 25 4
gpt4 key购买 nike

我的应用程序使用正则表达式并行搜索多个文件,await Task.WhenAll(filePaths.Select(FindThings));

FindThings 中,它花费大部分时间执行正则表达式搜索,因为这些文件的大小可能有数百 MB。

static async Task FindThings(string path) {
string fileContent = null;
try
{
using (var reader = File.OpenText(path))
fileContent = await reader.ReadToEndAsync();
}
catch (Exception e)
{
WriteLine(lineIndex, "{0}: Error {1}", filename, e);
return;
}

var exitMatches = _exitExp.Matches(fileContent);

foreach (Match exit in exitMatches)
{
if (_taskDelay > 0)
await Task.Delay(_taskDelay);

// [...]
  • 是否有 Regex 的异步版本或任何方式使其与 Tasks 正确协作?

为什么这很重要

我收到很多回复,表明我没有阐明为什么这很重要。以这个示例程序(使用 Nitro.Async 库)为例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nito.AsyncEx;

namespace Scrap
{
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}

static async void MainAsync(string[] args)
{
var tasks = new List<Task>();

var asyncStart = DateTime.Now;
tasks.Add(Task.WhenAll(Enumerable.Range(0, 10).Select(i =>
ShowIndexAsync(i, asyncStart))));

var start = DateTime.Now;
tasks.Add(Task.WhenAll(Enumerable.Range(0, 10).Select(i =>
ShowIndex(i, start))));

await Task.WhenAll(tasks);

Console.ReadLine();
}


static async Task ShowIndexAsync(int index, DateTime start)
{
Console.WriteLine("ShowIndexAsync: {0} ({1})",
index, DateTime.Now - start);
await Task.Delay(index * 100);
Console.WriteLine("!ShowIndexAsync: {0} ({1})",
index, DateTime.Now - start);
}

static Task ShowIndex(int index, DateTime start)
{
return Task.Factory.StartNew(() => {
Console.WriteLine("ShowIndex: {0} ({1})",
index, DateTime.Now - start);
Task.Delay(index * 100).Wait();
Console.WriteLine("!ShowIndex: {0} ({1})",
index, DateTime.Now - start);
});
}
}
}

所以这会调用 ShowIndexAsync 10 次,然后调用 ShowIndex 10 次并等待它们完成。ShowIndexAsync 是“异步到核心”而 ShowIndex 不是,但它们都对任务进行操作。这里的阻塞操作是 Task.Delay,区别在于一个等待该任务,而另一个 .Wait() 在任务内部。

您希望第一个排队的 (ShowIndexAsync) 先完成,但您错了。

ShowIndexAsync: 0 (00:00:00.0060000)
!ShowIndexAsync: 0 (00:00:00.0070000)
ShowIndexAsync: 1 (00:00:00.0080000)
ShowIndexAsync: 2 (00:00:00.0110000)
ShowIndexAsync: 3 (00:00:00.0110000)
ShowIndexAsync: 4 (00:00:00.0120000)
ShowIndexAsync: 5 (00:00:00.0130000)
ShowIndexAsync: 6 (00:00:00.0130000)
ShowIndexAsync: 7 (00:00:00.0140000)
ShowIndexAsync: 8 (00:00:00.0150000)
ShowIndexAsync: 9 (00:00:00.0150000)
ShowIndex: 0 (00:00:00.0020000)
!ShowIndex: 0 (00:00:00.0020000)
ShowIndex: 1 (00:00:00.0030000)
!ShowIndex: 1 (00:00:00.1100000)
ShowIndex: 2 (00:00:00.1100000)
!ShowIndex: 2 (00:00:00.3200000)
ShowIndex: 3 (00:00:00.3200000)
!ShowIndex: 3 (00:00:00.6220000)
ShowIndex: 4 (00:00:00.6220000)
!ShowIndex: 4 (00:00:01.0280000)
ShowIndex: 5 (00:00:01.0280000)
!ShowIndex: 5 (00:00:01.5420000)
ShowIndex: 6 (00:00:01.5420000)
!ShowIndex: 6 (00:00:02.1500000)
ShowIndex: 7 (00:00:02.1510000)
!ShowIndex: 7 (00:00:02.8650000)
ShowIndex: 8 (00:00:02.8650000)
!ShowIndex: 8 (00:00:03.6660000)
ShowIndex: 9 (00:00:03.6660000)
!ShowIndex: 9 (00:00:04.5780000)
!ShowIndexAsync: 1 (00:00:04.5950000)
!ShowIndexAsync: 2 (00:00:04.5960000)
!ShowIndexAsync: 3 (00:00:04.5970000)
!ShowIndexAsync: 4 (00:00:04.5970000)
!ShowIndexAsync: 5 (00:00:04.5980000)
!ShowIndexAsync: 6 (00:00:04.5990000)
!ShowIndexAsync: 7 (00:00:04.5990000)
!ShowIndexAsync: 8 (00:00:04.6000000)
!ShowIndexAsync: 9 (00:00:04.6010000)

为什么会这样?

任务调度程序只会使用这么多的实际线程。 “await”编译成协作式多任务状态机。如果您有一个未等待的阻塞操作,在此示例中 Task.Delay(...).Wait(),但在我的问题中,Regex 匹配,它不会合作并让任务调度程序正确管理任务。

如果我们将示例程序更改为:

    static async void MainAsync(string[] args)
{
var asyncStart = DateTime.Now;
await Task.WhenAll(Enumerable.Range(0, 10).Select(i =>
ShowIndexAsync(i, asyncStart)));

var start = DateTime.Now;
await Task.WhenAll(Enumerable.Range(0, 10).Select(i =>
ShowIndex(i, start)));

Console.ReadLine();
}

然后我们的输出变为:

ShowIndexAsync: 0 (00:00:00.0050000)
!ShowIndexAsync: 0 (00:00:00.0050000)
ShowIndexAsync: 1 (00:00:00.0060000)
ShowIndexAsync: 2 (00:00:00.0080000)
ShowIndexAsync: 3 (00:00:00.0090000)
ShowIndexAsync: 4 (00:00:00.0090000)
ShowIndexAsync: 5 (00:00:00.0100000)
ShowIndexAsync: 6 (00:00:00.0110000)
ShowIndexAsync: 7 (00:00:00.0110000)
ShowIndexAsync: 8 (00:00:00.0120000)
ShowIndexAsync: 9 (00:00:00.0120000)
!ShowIndexAsync: 1 (00:00:00.1150000)
!ShowIndexAsync: 2 (00:00:00.2180000)
!ShowIndexAsync: 3 (00:00:00.3160000)
!ShowIndexAsync: 4 (00:00:00.4140000)
!ShowIndexAsync: 5 (00:00:00.5190000)
!ShowIndexAsync: 6 (00:00:00.6130000)
!ShowIndexAsync: 7 (00:00:00.7190000)
!ShowIndexAsync: 8 (00:00:00.8170000)
!ShowIndexAsync: 9 (00:00:00.9170000)
ShowIndex: 0 (00:00:00.0030000)
!ShowIndex: 0 (00:00:00.0040000)
ShowIndex: 3 (00:00:00.0060000)
ShowIndex: 4 (00:00:00.0090000)
ShowIndex: 2 (00:00:00.0100000)
ShowIndex: 1 (00:00:00.0100000)
ShowIndex: 5 (00:00:00.0130000)
ShowIndex: 6 (00:00:00.0130000)
ShowIndex: 7 (00:00:00.0150000)
ShowIndex: 8 (00:00:00.0180000)
!ShowIndex: 7 (00:00:00.7660000)
!ShowIndex: 6 (00:00:00.7660000)
ShowIndex: 9 (00:00:00.7660000)
!ShowIndex: 2 (00:00:00.7660000)
!ShowIndex: 5 (00:00:00.7660000)
!ShowIndex: 4 (00:00:00.7660000)
!ShowIndex: 3 (00:00:00.7660000)
!ShowIndex: 1 (00:00:00.7660000)
!ShowIndex: 8 (00:00:00.8210000)
!ShowIndex: 9 (00:00:01.6700000)

请注意异步调用如何有一个很好的均匀结束时间分布,但非异步代码却没有。任务调度程序被阻塞,因为它不会创建额外的真实线程,因为它期待合作。

我不希望它占用更少的 CPU 时间等,但我的目标是让 FindThings 在协作庄园中进行多任务处理,即,使其“与核心异步”。 "

最佳答案

正则表达式搜索是一个受 CPU 限制的操作,因此它们需要时间。您可以使用 Task.Run 将工作推到后台线程,从而使您的 UI 保持响应,但这不会帮助他们更快地进行。

由于您的搜索已经并行进行,因此您可能无能为力。您可以尝试使用异步文件读取来减少线程池中阻塞线程的数量,但这可能不会产生很大的影响。

您当前的代码正在调用 ReadToEndAsync 但它需要打开文件以进行异步访问(即,使用 FileStream 构造函数并通过传递true 用于 isAsync 参数或 FileOptions.Asynchronous 用于 options 参数。

关于c# - C# 中是否存在异步正则表达式,它们对我的情况有帮助吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25876719/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com