C# 完成无止境任务的最佳方式

C# 完成无止境任务的最佳方式,c#,task,C#,Task,我有一个任务输出任务。任务读取StreamReader(使用StreamReader.readlinesync())的输出 它仅以这种方式工作: var outputTask = plinkInstance.StandardOutput.ReadLineAsync().ContinueWith(hasOutputReaded); Action<Task<string>> hasOutputReaded = null; hasOutputReaded = (previou

我有一个任务
输出任务
。任务读取
StreamReader
(使用
StreamReader.readlinesync()
)的输出

它仅以这种方式工作:

var outputTask = plinkInstance.StandardOutput.ReadLineAsync().ContinueWith(hasOutputReaded);

Action<Task<string>> hasOutputReaded = null;
hasOutputReaded = (previousTask) =>
{
    resetTimer.Invoke();
    _outputLines.Add(previousTask.Result);
    previousTask = plinkInstance.StandardOutput.ReadLineAsync();
    previousTask.ContinueWith(hasOutputReaded);
};
方法呢

private static void readUntilEnd(StreamReader stream, System.Timers.Timer timer, CancellationToken canelToken)
{
    char[] buffer = new char[1];
    stream.ReadAsync(buffer, 0, 1);
    int cooldown = 0;

    while (!canelToken.IsCancellationRequested)
    {
        if (buffer[0] != '\0')
        {
            readAChar(buffer[0]);
            buffer[0] = '\0';
            stream.ReadAsync(buffer, 0, 1);

            timer.Stop();
            timer.Start();
            cooldown = 0;
         }
         else
         {
             if (cooldown < 100)
                 cooldown++;
         }

          if (cooldown > 0)
              Thread.Sleep(cooldown);
    }
}
private static void readUntilEnd(StreamReader stream、System.Timers.Timer Timer、CancellationToken canelToken)
{
char[]buffer=新字符[1];
ReadAsync(缓冲区,0,1);
int冷却时间=0;
而(!canelToken.iscancellationrequest)
{
如果(缓冲区[0]!='\0')
{
readAChar(缓冲区[0]);
缓冲区[0]='\0';
ReadAsync(缓冲区,0,1);
timer.Stop();
timer.Start();
冷却时间=0;
}
其他的
{
如果(冷却时间<100)
冷却++;
}
如果(冷却时间>0)
线程。睡眠(冷却);
}
}

为什么我需要
取消令牌
?我还可以传递bool对象,或者不传递?

既然您正在异步运行连续任务,为什么不让它成为一个无休止的循环呢

Task.Run(() =>
         {
            while (true)
            {
               var output = await READ_LINE_ASYNCHRONOUSLY();
               _outputLines.Add(output);
            }
         });
如果您需要某种方法来打破循环(我想您可能需要),请使用
CancellationToken
,如下所述:

编辑:以下是执行您可能希望执行的操作的完整代码:

Task.Run(() => ReadUntilEnd(streamReader, cancellationTokenSource.Token),
         cancellationTokenSource.Token);

//...

private static async Task ReadUntilEnd(StreamReader streamReader, 
                                       CancellationToken cancellationToken)
{
    char[] buffer = new char[1];
    while (!cancellationToken.IsCancellationRequested)
    {
        await streamReader.ReadAsync(buffer, 0, 1);
        readAChar(buffer[0]);
    }
}
private static async Task readUntilEnd(StreamReader stream,System.Timers.Timer Timer,CancellationToken canelToken)
{
char[]buffer=新字符[1];
Task readTask=stream.ReadAsync(缓冲区,0,1);
int冷却时间=5;
而(!canelToken.iscancellationrequest)
{
如果(readTask.IsCompleted)
{
readAChar(缓冲区[0]);
缓冲区[0]='\0';
readTask=stream.ReadAsync(缓冲区,0,1);
timer.Stop();
timer.Start();
冷却时间=0;
}
其他的
{
如果(冷却时间<100)
冷却++;
}
如果(冷却时间>0)
等待任务。延迟(冷却,canelToken);
}
}

任务(在我第一次尝试时)是一个局部变量。所以垃圾收集器停止了循环(我猜)。但是在这里我必须写一个额外的取消。不,GC不会停止你的循环,因为你的任务一直在引用它自己,所以它对于垃圾收集是不可行的。只要你的应用程序(或者线程,如果你正在做更复杂的事情)在运行,它就会一直运行。我还简化了我的示例——如果出于某种原因,您希望有一个变量,而不是内联提供Task.Run()参数,那么您可以这样做。但对于如何以及何时终止任务,它仍然无能为力。新方法更好吗?(看第一篇帖子)@user6537157是的,因为它是我上面写的通用版本的一个具体实现。否,因为您在不等待结果的情况下启动异步方法(
ReadAsync
),但仍在尝试使用结果(通过访问
缓冲区
变量)。睡前阅读:,但简短的版本是:1。使您的
readUntilEnd
方法
异步任务
(而不是
void
)2。在每次调用
ReadAsync
@user6537157之前添加
wait
关键字。您的代码的一个重要问题是,它不会以确定的方式工作-有时它甚至可以正常工作,但有时它会漏掉一些行并读取同一行两次,因为您的代码是如何独立于流读取部分进行的。
Task.Run(() => ReadUntilEnd(streamReader, cancellationTokenSource.Token),
         cancellationTokenSource.Token);

//...

private static async Task ReadUntilEnd(StreamReader streamReader, 
                                       CancellationToken cancellationToken)
{
    char[] buffer = new char[1];
    while (!cancellationToken.IsCancellationRequested)
    {
        await streamReader.ReadAsync(buffer, 0, 1);
        readAChar(buffer[0]);
    }
}
private static async Task readUntilEnd(StreamReader stream, System.Timers.Timer timer, CancellationToken canelToken)
{
    char[] buffer = new char[1];
    Task readTask = stream.ReadAsync(buffer, 0, 1);
    int cooldown = 5;

    while (!canelToken.IsCancellationRequested)
    {
        if (readTask.IsCompleted)
        {
             readAChar(buffer[0]);

             buffer[0] = '\0';
             readTask = stream.ReadAsync(buffer, 0, 1);

             timer.Stop();
             timer.Start();

             cooldown = 0;
        }
        else
        {
            if (cooldown < 100)
                cooldown++;
        }

        if (cooldown > 0)
            await Task.Delay(cooldown, canelToken);
    }

}