AFAIK,它所知道的是,在某些时候,它SetResult或SetException方法被调用以Task<T>通过其Task属性完成暴露.
换句话说,它充当a Task<TResult>及其完成的生产者.
如果我需要一种方法来异步执行Func并有一个Task来表示该操作.
public static Task<T> RunAsync<T>(Func<T> function)
{
if (function == null) throw new ArgumentNullException(“function”);
var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
T result = function();
tcs.SetResult(result);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
可以使用*如果我没有Task.Factory.StartNew- 但我确实有Task.Factory.StartNew.
题:
可有人请举例相关的情景解释直接到TaskCompletionSource
而不是一个假想中,我没有的情况 Task.Factory.StartNew?
我有一个blackbox对象,它暴露了一个异步操作的方法,并在操作完成时触发一个事件.我已经将它包装到一个Task<OpResult> BlackBoxOperationAysnc()使用TaskCompletionSource 的方法中 - 效果很好.
但是,在那个异步包装器中,如果在给定的超时后没有收到事件,我想管理用超时错误完成异步调用.目前我使用计时器管理它:
public Task<OpResult> BlackBoxOperationAysnc() {
var tcs = new TaskCompletionSource<TestResult>();
const int timeoutMs = 20000;
Timer timer = new Timer(_ => tcs.TrySetResult(OpResult.Timeout),
null, timeoutMs, Timeout.Infinite);
EventHandler<EndOpEventArgs> eventHandler = (sender, args) => {
...
tcs.TrySetResult(OpResult.BlarBlar);
}
blackBox.EndAsyncOpEvent += eventHandler;
blackBox.StartAsyncOp();
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
这是管理超时的唯一方法吗?有没有设置我自己的计时器 - 我在TaskCompletionSource中看不到任何超时?
有关功能和含义的区别是什么
TaskCompletionSource + SetResult vs Task + FromResult
在SendAsync方法?
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
var response = new HttpResponseMessage(HttpStatusCode.Forbidden) {ReasonPhrase = "HTTPS Required"};
var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
taskCompletionSource.SetResult(response);
return taskCompletionSource.Task;
}
return base.SendAsync(request, cancellationToken);
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!request.RequestUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
{
HttpResponseMessage reply = request.CreateErrorResponse(HttpStatusCode.BadRequest, "HTTPS is required for security reason.");
return Task.FromResult(reply);
}
return base.SendAsync(request, cancellationToken);
}
Run Code Online (Sandbox Code Playgroud) c# task-parallel-library async-await asp.net-web-api taskcompletionsource
我有这样的代码(在这里简化)等待完成任务:
var task_completion_source = new TaskCompletionSource<bool>();
observable.Subscribe(b =>
{
if (b)
task_completion_source.SetResult(true);
});
await task_completion_source.Task;
Run Code Online (Sandbox Code Playgroud)
这个想法是订阅并等待true布尔流.这完成了"任务",我可以继续前进await.
但是我想取消 - 但不是订阅,而是等待.我想传递取消令牌(不知何故),task_completion_source所以当我取消令牌源时,await将继续前进.
怎么做?
更新:CancellationTokenSource这个代码是外部的,我这里所有的都是来自它的令牌.
c# asynchronous async-await cancellationtokensource taskcompletionsource
(这是对这个问题的新尝试,现在更好地证明了这个问题.)
假设我们有一个错误的任务(var faultedTask = Task.Run(() => { throw new Exception("test"); });),我们等待它.await将解压缩AggregateException并抛出基础异常.它会抛出faultedTask.Exception.InnerExceptions.First().
根据源代码,ThrowForNonSuccess它将通过执行任何存储ExceptionDispatchInfo来执行此操作,可能是为了保留良好的堆栈跟踪.AggregateException如果没有,它将不会打开包装ExceptionDispatchInfo.
这个事实本身是令人惊讶的,因为我的文档指出,第一异常始终抛出:https://msdn.microsoft.com/en-us/library/hh156528.aspx?f=255&MSPPError=-2147217396事实证明,await即可AggregateException但是,抛出,这是没有记录的行为.
当我们想要创建代理任务并设置它的异常时,这就成了一个问题:
var proxyTcs = new TaskCompletionSource<object>();
proxyTcs.SetException(faultedTask.Exception);
await proxyTcs.Task;
Run Code Online (Sandbox Code Playgroud)
这将引发AggregateException而await faultedTask;将抛出测试异常.
如何创建我可以随意完成的代理任务,这将反映原始任务的异常行为?
最初的行为是:
await 将抛出第一个内部异常.Task.Exception.InnerExceptions.(这个问题的早期版本遗漏了这个要求.)这是一个总结了调查结果的测试:
[TestMethod]
public void ExceptionAwait()
{
ExceptionAwaitAsync().Wait();
}
static async Task ExceptionAwaitAsync()
{
//Task has multiple exceptions.
var faultedTask = Task.WhenAll(Task.Run(() …Run Code Online (Sandbox Code Playgroud) .net c# task-parallel-library async-await taskcompletionsource
我想用来TaskCompletionSource包装MyService哪个是简单的服务:
public static Task<string> ProcessAsync(MyService service, int parameter)
{
var tcs = new TaskCompletionSource<string>();
//Every time ProccessAsync is called this assigns to Completed!
service.Completed += (sender, e)=>{ tcs.SetResult(e.Result); };
service.RunAsync(parameter);
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
这段代码第一次运行良好.但是我第二次ProcessAsync简单地Completed再次调用事件处理程序(service每次使用相同的变量),因此它将执行两次!并且它第二次抛出此异常:
在已经完成时尝试转换任务最终状态
我不确定,我应该tcs像这样声明一个类级变量:
TaskCompletionSource<string> tcs;
public static Task<string> ProccessAsync(MyService service, int parameter)
{
tcs = new TaskCompletionSource<string>();
service.Completed -= completedHandler;
service.Completed += completedHandler;
return tcs.Task;
}
private void completedHandler(object sender, CustomEventArg e)
{ …Run Code Online (Sandbox Code Playgroud) 对于我的内心运作方式,我有些不清楚TaskCompletionSource<>.
当Task<>使用the 创建一个简单的时候Factory,我希望这个任务在一个线程池中排队,除非我指定TaskCreationOptions.LongRunning,它将在一个新的线程中运行.
我的理解TaskCompletionSource是,我负责在任务结束或失败时触发,并且我完全控制如何管理线程.然而,ctor TaskCompletionSource允许我指定一个TaskCreationOptions,这让我感到困惑,因为我期望Scheduler无法处理任务本身.
TaskCreationOptions在一个上下文中的目的是TaskCompletionSource<>什么?
这是一个使用示例:
public Task<WebResponse> Download(string url)
{
TaskCompletionSource<WebResponse> tcs =
new TaskCompletionSource<WebResponse>(TaskCreationOptions.LongRunning);
var client = (HttpWebRequest)HttpWebRequest.Create(url);
var async = client.BeginGetResponse(o =>
{
try
{
WebResponse resp = client.EndGetResponse(o);
tcs.SetResult(resp);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}, null);
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud) 我有一个函数,我使用await关键字异步调用:
public Task<StatePropertyEx> RequestStateForEntity(EntityKey entity, string propName)
{
var tcs = new TaskCompletionSource<StateInfo>();
try
{
var propInstance = BuildCacheKey(entity, propName);
StateCacheItem cacheItem;
if (_stateCache.TryGetValue(propInstance, out cacheItem))
{
tcs.SetResult( new StateInfo (cacheItem.State.Name, cacheItem.State.Value) );
return tcs.Task;
}
//state not found in local cache so save the tcs for later and request the state
var cacheKey = BuildCacheKey(entity, propName);
_stateRequestItemList.TryAdd(cacheKey, new StateRequestItem(entity, propName, tcs));
_evtClient.SubmitStateRequest(entity, propName);
return tcs.Task;
}
catch (Exception ex)
{
tcs.SetException(ex);
return tcs.Task;
}
}
Run Code Online (Sandbox Code Playgroud)
该函数查看它是否具有所需的信息,如果有,则返回它.如果它没有详细信息,它会发送一个最终应该作为事件发出的请求.此时,我的代码(未显示)找到存储的TaskCompletionSource项,设置结果并返回它.这一切都运行正常但我现在被要求考虑一种情况,当我通过"_evtClient.SubmitStateRequest(entity,propName);"行请求状态时,可能永远不会返回回复.我需要实现某种超时机制,以便我可以取消TCS任务,以便函数调用者可以正常失败.我一直在寻找SO和互联网,找不到任何看起来正确的东西.我现在不确定是否需要以不同的方式重构上述代码.任何人都可以建议或指向类似的情况?
调用上述函数的代码可以在单击中调用它,如下所示:
var stateProperty …Run Code Online (Sandbox Code Playgroud) 该async关键字也导致CIL改变(即使有方法内部没有的await),但它主要是允许await存在.
但我没想到会发生以下情况:
static void Main(string[] args)
{
Task t = Go();
t.Wait();
}
static async Task Go()
{
Console.WriteLine(1);
await AAA(3000);
Console.WriteLine(2);
}
static Task<object> AAA(int a) // <--- No `async`
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
这个印刷品:
1
(wait)
2
Run Code Online (Sandbox Code Playgroud)
但如果我改变
static Task<object> AAA(int a)
Run Code Online (Sandbox Code Playgroud)
至
static async Task<object> AAA(int a)
Run Code Online (Sandbox Code Playgroud)
它打印:
1
2
(no wait)
Run Code Online (Sandbox Code Playgroud)
题
为什么我没有看到延迟?TCS仅在三秒后解决.同时,任务没有得到解决,应该等待.
.net c# task-parallel-library async-await taskcompletionsource
我发现我无法区分受控/合作与"不受控制"的任务/代表取消,而无需检查特定任务或代表背后的来源.
具体来说,我总是假设当OperationCanceledException从"低级操作"中捕获抛出时,如果引用的令牌无法与当前操作的令牌匹配,那么它应该被解释为失败/错误.这是它放弃(退出)的"低级操作"的声明,但不是因为你要求它这样做.
不幸的是,TaskCompletionSource无法关联一个CancellationToken作为取消的原因.因此,没有内置调度程序支持的任何任务无法传达其取消的原因,并且可能错误地将合作取消误报为错误.
更新:由于.NET 4.6 TaskCompletionSource 可以关联起来CancellationToken ,如果新的过载SetCanceled或TrySetCanceled使用.
例如以下内容
public Task ShouldHaveBeenAsynchronous(Action userDelegate, CancellationToken ct)
{
var tcs = new TaskCompletionSource<object>();
try
{
userDelegate();
tcs.SetResult(null); // Indicate completion
}
catch (OperationCanceledException ex)
{
if (ex.CancellationToken == ct)
tcs.SetCanceled(); // Need to pass ct here, but can't
else
tcs.SetException(ex);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
private void OtherSide()
{
var cts …Run Code Online (Sandbox Code Playgroud) c# asynchronous task task-parallel-library taskcompletionsource