对TaskCompletionSource完全不清楚,msdn上有介绍:https://technet.microsoft.com/zh-cn/library/dd449174(v=vs.110).aspx,
https://www.cnblogs.com/farb/p/4870421.html,
https://msdn.microsoft.com/zh-cn/library/dd997423(v=vs.100).aspx,
https://msdn.microsoft.com/zh-cn/library/dd537609(v=vs.100).aspx,
https://msdn.microsoft.com/zh-cn/library/dd997423(v=vs.100).aspx中有一句:TaskCompletionSource<TResult> 创建的任何任务将由 TaskCompletionSource 启动,因此,用户代码不应在该任务上调用 Start 方法。
还有一篇TaskCompletionSource相关的异步编程好帖子 全面解析C#中的异步编程 https://www.cnblogs.com/xiaoyaojian/p/4603238.html 其中有一段代码做实验应该会有收获:
static async void ReadAssignedFile()
{
byte[] buffer;
try
{
double length = await ReadFileAsync("SomeFileDoNotExisted.txt", out buffer);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static Task<double> ReadFileAsync(string filePath,out byte[] buffer)
{
Stream stream = File.Open(filePath, FileMode.Open);
buffer = new byte[stream.Length];
var tcs = new TaskCompletionSource<double>();
stream.BeginRead(buffer, 0, buffer.Length, arr =>
{
try
{
var length = stream.EndRead(arr);
tcs.SetResult(stream.Length);
}
catch (IOException ex)
{
tcs.SetException(ex);
}
}, null);
return tcs.Task;
}
https://msdn.microsoft.com/zh-cn/magazine/ff959203.aspx
https://msdn.microsoft.com/zh-cn/library/ee622454(v=vs.100).aspx 也有介绍,现在开始做实验:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TaskCompletionSourceDemo
{
class WebDataDownloader
{
static void Main()
{
WebDataDownloader downloader = new WebDataDownloader();
string[] addresses = { "http://www.baidu.com", "http://www.yahoo.com",
"http://www.sina.com", "http://www.qq.com" };
CancellationTokenSource cts = new CancellationTokenSource();
// Create a UI thread from which to cancel the entire operation
Task.Factory.StartNew(() =>
{
Console.WriteLine("Press c to cancel");
if (Console.ReadKey().KeyChar == 'c')
cts.Cancel();
});
// Using a neutral search term that is sure to get some hits.
Task<string[]> webTask = downloader.GetWordCounts(addresses, "the", cts.Token);
// Do some other work here unless the method has already completed.
if (!webTask.IsCompleted)
{
// Simulate some work.
Thread.SpinWait(5000000);
}
string[] results = null;
try
{
results = webTask.Result;
}
catch (AggregateException e)
{
foreach (var ex in e.InnerExceptions)
{
OperationCanceledException oce = ex as OperationCanceledException;
if (oce != null)
{
if (oce.CancellationToken == cts.Token)
{
Console.WriteLine("Operation canceled by user.");
}
}
else
Console.WriteLine(ex.Message);
}
}
if (results != null)
{
foreach (var item in results)
Console.WriteLine(item);
}
Console.ReadKey();
}
Task<string[]> GetWordCounts(string[] urls, string name, CancellationToken token)
{
TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();
WebClient[] webClients = new WebClient[urls.Length];
// If the user cancels the CancellationToken, then we can use the
// WebClient's ability to cancel its own async operations.
token.Register(() =>
{
foreach (var wc in webClients)
{
if (wc != null)
wc.CancelAsync();
}
});
object m_lock = new object();
int count = 0;
List<string> results = new List<string>();
for (int i = 0; i < urls.Length; i++)
{
webClients[i] = new WebClient();
#region callback
// Specify the callback for the DownloadStringCompleted
// event that will be raised by this WebClient instance.
webClients[i].DownloadStringCompleted += (obj, args) =>
{
if (args.Cancelled == true)
{
tcs.TrySetCanceled();
return;
}
else if (args.Error != null)
{
// Pass through to the underlying Task
// any exceptions thrown by the WebClient
// during the asynchronous operation.
tcs.TrySetException(args.Error);
return;
}
else
{
// Split the string into an array of words,
// then count the number of elements that match
// the search term.
string[] words = null;
words = args.Result.Split(' ');
string NAME = name.ToUpper();
int nameCount = (from word in words.AsParallel()
where word.ToUpper().Contains(NAME)
select word)
.Count();
// Associate the results with the url, and add new string to the array that
// the underlying Task object will return in its Result property.
results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name));
}
// If this is the last async operation to complete,
// then set the Result property on the underlying Task.
lock (m_lock)
{
count++;
if (count == urls.Length)
{
tcs.TrySetResult(results.ToArray());
}
}
};
#endregion
// Call DownloadStringAsync for each URL.
Uri address = null;
try
{
address = new Uri(urls[i]);
// Pass the address, and also use it for the userToken
// to identify the page when the delegate is invoked.
webClients[i].DownloadStringAsync(address, address);
}
catch (UriFormatException ex)
{
// Abandon the entire operation if one url is malformed.
// Other actions are possible here.
tcs.TrySetException(ex);
return tcs.Task;
}
}
// Return the underlying Task. The client code
// waits on the Result property, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}
}
}
程序执行的结果如下:
Press c to cancel
http://www.baidu.com/ has 1 instances of the
http://www.qq.com/ has 72 instances of the
http://www.sina.com/ has 2 instances of the
http://www.yahoo.com/ has 0 instances of the