C#任务工厂超时

C#任务工厂超时,c#,timeout,task,factory,C#,Timeout,Task,Factory,我必须在线程中执行一个长进程操作,并通过将结果返回给函数继续。这是我的密码: Task<ProductEventArgs>.Factory.StartNew(() => { try { // long operation which return new ProductEventArgs with a list of product } catch (Exception e)

我必须在线程中执行一个长进程操作,并通过将结果返回给函数继续。这是我的密码:

Task<ProductEventArgs>.Factory.StartNew(() =>
    {
        try
        {
             // long operation which return new ProductEventArgs with a list of product

        }
        catch (Exception e)
        {
            return new ProductEventArgs() { E = e };
        }

    }).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
如果达到超时时间。 无法使用wait/async。
非常感谢

您可以并行运行
任务。延迟(超时)
任务,并检查首先完成的任务(
Task.whenay()
在这种情况下非常方便):

public void FetchProduct(TimeSpan超时)
{
var fetchTask=Task.Factory.StartNew(
() =>
{
尝试
{
//返回带有产品列表的新ProductEventArgs的长操作
}
捕获(例外e)
{
返回新的ProductEventArgs(){E=E};
}
});
任务结果任务;
如果(超时!=超时。无限期)
{
var timeoutTask=Task.Delay(超时);
resultTask=Task.WhenAny(resultTask,timeoutTask)。是否继续(
t=>
{
//完成的任务是
if(t.Result==fetchTask)
{
返回fetchTask.Result;
}
其他的
{
返回新的ProductEventArgs(){E=new TimeoutException()};
}
});
}
其他的
{
resultTask=fetchTask;
}
resultTask.ContinueWith(x=>handleResult(x.Result),TaskScheduler.FromCurrentSynchronizationContext());
}

请注意,此解决方案没有任何取消逻辑,即使超时,长时间运行的任务仍将运行。

此代码执行您在此处表达的操作:

var timeout = TimeSpan.FromSeconds(5);

var actualTask = new Task<ProductEventArgs>(() =>
{
    var longRunningTask = new Task<ProductEventArgs>(() =>
    {
        try
        {
            Thread.Sleep(TimeSpan.FromSeconds(10)); // simulates the long running computation
            return new ProductEventArgs();
        }
        catch (Exception e)
        {
            return new ProductEventArgs() { E = e };
        }
    }, TaskCreationOptions.LongRunning);

    longRunningTask.Start();

    if (longRunningTask.Wait(timeout)) return longRunningTask.Result;

    return new ProductEventArgs() { E = new Exception("timed out") };
});

actualTask.Start();

actualTask.Wait();

Console.WriteLine("{0}", actualTask.Result.E); // handling E
var timeout=TimeSpan.FromSeconds(5);
var actualTask=新任务(()=>
{
var longRunningTask=新任务(()=>
{
尝试
{
Thread.Sleep(TimeSpan.FromSeconds(10));//模拟长时间运行的计算
返回新的ProductEventArgs();
}
捕获(例外e)
{
返回新的ProductEventArgs(){E=E};
}
},TaskCreationOptions.LongRunning);
longRunningTask.Start();
if(longRunningTask.Wait(timeout))返回longRunningTask.Result;
返回新的ProductEventArgs(){E=新异常(“超时”)};
});
actualTask.Start();
实际任务。等待();
Console.WriteLine(“{0}”,actualTask.Result.E);//处理E
如您所见,
longRunningTask
是使用
TaskCreationOptions.LongRunning
选项创建的。这样,它将有一个专用的
线程
来执行它,并且不会因为占用线程太长时间而干扰
线程池
的正常行为,这是UI等其他东西所需要的这对于长时间运行的任务很重要


注意:然后您可以使用
ContinueWith
处理
实际任务
,但我想在这里表达其本质。

您应该使用
取消令牌
s:

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var token = cts.Token;
Task<ProductEventArgs>.Factory.StartNew(() =>
{
    try
    {
        // occasionally, execute this line:
        token.ThrowIfCancellationRequested();
    }
    catch (OperationCanceledException)
    {
        return new ProductEventArgs() { E = new Exception("timeout") };
    }
    catch (Exception e)
    {
        return new ProductEventArgs() { E = e };
    }

}).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
var cts=new CancellationTokenSource(TimeSpan.FromSeconds(10));
var-token=cts.token;
Task.Factory.StartNew(()=>
{
尝试
{
//偶尔,执行以下命令行:
token.ThrowIfCancellationRequested();
}
捕获(操作取消异常)
{
返回新的ProductEventArgs(){E=new Exception(“timeout”)};
}
捕获(例外e)
{
返回新的ProductEventArgs(){E=E};
}
}).ContinueWith((x)=>handleResult(x.Result),TaskScheduler.FromCurrentSynchronizationContext());

您可以将返回的任务对象用于StartNew方法,然后使用user Wait方法来确定超时时间

Task<ProductEventArgs> task = Task<ProductEventArgs>.Factory.StartNew(() => {...});
if (!Task.Wait(new TimeSpan(0,0,1,0)) // wait for 1 minute
{
   // throw exception or something else if timeout
}
Task Task=Task.Factory.StartNew(()=>{…});
if(!Task.Wait(new TimeSpan(0,0,1,0))//等待1分钟
{
//如果超时,则抛出异常或其他内容
}

只需在主任务(代理)中启动另一个任务:

Task.Factory.StartNew(()=>
{
//返回字符串结果
var tsk=新任务(()=>{return veryiimportantthingstodo();});
尝试
{
tsk.Start();
如果(!tsk.等待(5000))
抛出新的TimeoutException();
返回tsk.Result;
}
捕获(超时异常)
{
//Jabba Dabba Doooooohh
}
返回“”;
}).ContinueWith((o)=>字符串结果=o.result));

我完全同意这一点。希望OP能做到这一点——我的回答是基于(可能是鲁莽的)假设,OP正在用他的控制调用一些不支持超时或取消的代码,所以我假设他不能这样做。我希望他能在您的代码中,我只需要将令牌作为startnew方法的第二个参数,对吗?因为不是你写的。如果我这样做了,例如timestan为0秒,我在handle result(x.result)上有一个aggregateException。谢谢,在您的情况下,您不应该将
取消令牌
传递给
开始新建
。如果您这样做(如您所观察到的),则已取消的
CancellationToken
实际上会在任务开始之前取消任务。但您不希望任务完成取消,因此这不是您想要的行为。您的代码将在.Net 4.5及更高版本上运行,因为在.Net 4.0上,CancellationTokenSource只有默认构造函数。爱您:-*我对C有点陌生,对线程管理有更多了解,您让我开心!
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var token = cts.Token;
Task<ProductEventArgs>.Factory.StartNew(() =>
{
    try
    {
        // occasionally, execute this line:
        token.ThrowIfCancellationRequested();
    }
    catch (OperationCanceledException)
    {
        return new ProductEventArgs() { E = new Exception("timeout") };
    }
    catch (Exception e)
    {
        return new ProductEventArgs() { E = e };
    }

}).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
Task<ProductEventArgs> task = Task<ProductEventArgs>.Factory.StartNew(() => {...});
if (!Task.Wait(new TimeSpan(0,0,1,0)) // wait for 1 minute
{
   // throw exception or something else if timeout
}
Task.Factory.StartNew(() => 
        {
            // returns a string result
            var tsk = new Task<string>(() => { return VeryImportantThingsToDo(); });
            try
            {
                tsk.Start();
                if (!tsk.Wait(5000))
                    throw new TimeoutException();
                return tsk.Result;
            }
            catch (TimeoutException)
            {
                // Jabba Dabba Doooooooohhhhhh
            }

            return "<unknown>";
        }).ContinueWith((o) => string result = o.Result));