C# 如何启动N个任务(或线程)来运行可能返回无用结果的相同方法?

C# 如何启动N个任务(或线程)来运行可能返回无用结果的相同方法?,c#,.net-core,task-parallel-library,C#,.net Core,Task Parallel Library,我有一些随机函数,它们返回一个可能。当它产生有用的结果时,可能包含该结果 可能是这样实现的: public readonly struct Maybe<T> { public readonly bool ContainsValue; public readonly T Value; [MethodImpl(MethodImplOptions.AggressiveInlining)] public Maybe(bool containsValue,

我有一些随机函数,它们返回一个
可能
。当它产生有用的结果时,可能包含该结果

可能
是这样实现的:

public readonly struct Maybe<T> {

    public readonly bool ContainsValue;
    public readonly T Value;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public Maybe(bool containsValue, T value) {
        ContainsValue = containsValue;
        Value = value;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Maybe<T> Just(T value) {
        return new Maybe<T>(
            containsValue: true,
            value: value);
    }

    public static Maybe<T> Empty { get; } = new Maybe<T>(
        containsValue: false,
        value: default
        );

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static implicit operator Maybe<T>(T value) => Maybe.Just(value);
}
我将此贴在codereview上,征求改进建议,但一无所获。 我觉得这段代码很难看,可能有更好的方法可以做到这一点。 是否有更优雅的方法(不使用外部库)来实现这一点?
我正在使用C#7.2瞄准.Net Core 2.2

我已经更新了代码并发布在下面。它没有经过测试,但答案就在那里。你应该能够按原样跑步,但如果不能,就从中得到你需要的东西

  • 首先,您需要添加一个
    CancellationTokenSource
    ,并将
    Token
    传递给
    任务
    启动,以便您可以(从框架)向他们发出停止的信号
    透视图)
  • 然后,您需要在
    while
    循环中监视
    CancellationTokenSource
    您自己,以手动停止任务
  • Task.WaitAny
    返回执行的
    任务的索引
    已完成,因此您不需要通过迭代来找到它
  • 您也已经返回了
    可能。如果
    任务
    结束时没有结果,因此无需测试
    ContainsValue
    ;只是 返回
    结果
代码在下面,并记录在我进行更改的地方

//Make a cancellation token source to signal other tasks to cancel.
CancellationTokenSource cts = new CancellationTokenSource();
for (int i = 0; i < tasks.Length; i++)
{
    tasks[i] = Task.Run(() => {
        while (!cts.IsCancellationRequested) //Monitor for the cancellation token source to signal canceled.
        {
            if (retries >= maximumRetries || finished > 0)
                return Maybe<T>.Empty;

            var attempt = func();
            if (attempt.ContainsValue)
            {
                Interlocked.Increment(ref finished);
                return attempt;
            }
            else
            {
                Interlocked.Increment(ref retries);
            }
        }
        return Maybe<T>.Empty;
    }, cts.Token); //Add the token to the task.
}

var completedTaskIndex = Task.WaitAny(tasks); //Task.WaitAny gives you the index of the Task that did complete.
cts.Cancel(); //Signal the remaining tasks to complete.
var completedTask = tasks[completedTaskIndex]; //Get the task that completed.
return completedTask.Result; //You're returning Maybe<T>.Emtpy from the Task if it fails so no need to check ContainsValue; just return the result.
//创建一个取消令牌源,以向其他任务发出取消的信号。
CancellationTokenSource cts=新的CancellationTokenSource();
for(int i=0;i{
while(!cts.IsCancellationRequested)//监视取消令牌源以发出取消信号。
{
如果(重试次数>=最大重试次数| |完成次数>0)
也许会回来。空的;
var尝试=func();
if(尝试.包含值)
{
联锁。增量(参考完成);
回击尝试;
}
其他的
{
联锁增量(参考重试次数);
}
}
也许会回来。空的;
},cts.Token);//将令牌添加到任务中。
}
var completedTaskIndex=Task.WaitAny(任务)//Task.WaitAny为您提供已完成任务的索引。
cts.Cancel()//发出完成剩余任务的信号。
var completedTask=tasks[completedTaskIndex]//获取已完成的任务。
返回completedTask.Result//如果任务失败,您可能会返回.Emtpy,因此无需检查ContainsValue;只需返回结果。

我已经更新了代码并发布在下面。它没有经过测试,但答案就在那里。你应该能够按原样跑步,但如果不能,就从中得到你需要的东西

  • 首先,您需要添加一个
    CancellationTokenSource
    ,并将
    Token
    传递给
    任务
    启动,以便您可以(从框架)向他们发出停止的信号
    透视图)
  • 然后,您需要在
    while
    循环中监视
    CancellationTokenSource
    您自己,以手动停止任务
  • Task.WaitAny
    返回执行的
    任务的索引
    已完成,因此您不需要通过迭代来找到它
  • 您也已经返回了
    可能。如果
    任务
    结束时没有结果,因此无需测试
    ContainsValue
    ;只是 返回
    结果
代码在下面,并记录在我进行更改的地方

//Make a cancellation token source to signal other tasks to cancel.
CancellationTokenSource cts = new CancellationTokenSource();
for (int i = 0; i < tasks.Length; i++)
{
    tasks[i] = Task.Run(() => {
        while (!cts.IsCancellationRequested) //Monitor for the cancellation token source to signal canceled.
        {
            if (retries >= maximumRetries || finished > 0)
                return Maybe<T>.Empty;

            var attempt = func();
            if (attempt.ContainsValue)
            {
                Interlocked.Increment(ref finished);
                return attempt;
            }
            else
            {
                Interlocked.Increment(ref retries);
            }
        }
        return Maybe<T>.Empty;
    }, cts.Token); //Add the token to the task.
}

var completedTaskIndex = Task.WaitAny(tasks); //Task.WaitAny gives you the index of the Task that did complete.
cts.Cancel(); //Signal the remaining tasks to complete.
var completedTask = tasks[completedTaskIndex]; //Get the task that completed.
return completedTask.Result; //You're returning Maybe<T>.Emtpy from the Task if it fails so no need to check ContainsValue; just return the result.
//创建一个取消令牌源,以向其他任务发出取消的信号。
CancellationTokenSource cts=新的CancellationTokenSource();
for(int i=0;i{
while(!cts.IsCancellationRequested)//监视取消令牌源以发出取消信号。
{
如果(重试次数>=最大重试次数| |完成次数>0)
也许会回来。空的;
var尝试=func();
if(尝试.包含值)
{
联锁。增量(参考完成);
回击尝试;
}
其他的
{
联锁增量(参考重试次数);
}
}
也许会回来。空的;
},cts.Token);//将令牌添加到任务中。
}
var completedTaskIndex=Task.WaitAny(任务)//Task.WaitAny为您提供已完成任务的索引。
cts.Cancel()//发出完成剩余任务的信号。
var completedTask=tasks[completedTaskIndex]//获取已完成的任务。
返回completedTask.Result//如果任务失败,您可能会返回.Emtpy,因此无需检查ContainsValue;只需返回结果。

谢谢您的建议!我没有注意到。WaitAny返回了index.np,很高兴它有帮助。谢谢你的建议!我没有注意到。WaitAny返回了index.np,很高兴它有帮助。