无法获取 TaskCompletionSource 的结果
Can not get results of TaskCompletionSource
您好,我遇到了以下问题:
我想执行类似于事务的操作。我想在收到外部 trigger.Therefore 后执行一些 async
操作 我正在使用 TaskCompletionSource
,它在表示触发器的方法中设置:TriggerTransaction
.
当我按下特定的控制台键时,此触发方法在 Main
线程池中被调用。
在我按下 A
关键字后,TriggerTransaction
被执行并且 TaskCompletionSource
-s 得到 set.Still 主线程不计算等待的两个总和任务。
class Program
{
public static Task<Task<int>> TransactionOperation1()
{
TaskCompletionSource<Task<int>> tcs = new TaskCompletionSource<Task<int>>();
tasks.Add(tcs);
Task<Task<int>> result = tcs.Task;
return result;
}
public static Task<Task<int>> TransactionOperation2()
{
TaskCompletionSource<Task<int>> tcs = new TaskCompletionSource<Task<int>>();
tasks.Add(tcs);
Task<Task<int>> result = tcs.Task;
return result;
}
public static async Task<int> ExecuteTransactionOnDB()
{
await Task.Delay(1000);
return 5;
}
public static async Task TriggerTransaction()
{
int value = await ExecuteTransactionOnDB();
foreach (var item in tasks)
{
item.SetResult(value);
}
}
public static List<dynamic> tasks = new List<dynamic>();
static async Task Main(string[] args)
{
Task<Task<int>> a = TransactionOperation1();
Task<Task<int>> b = TransactionOperation2();
Task.Run(async() =>
{
while (Console.ReadKey().Key != ConsoleKey.A) ;
await TriggerTransaction();
});
if (!File.Exists("D:\data.txt"))
{
File.Create("D:\data.txt");
}
using(FileStream stream=new FileStream("data.txt",FileMode.Append,FileAccess.Write))
{
int sum=await await a + await await b;//thread wont pass this line when tasks are set.
ReadOnlyMemory<byte> bytes = Encoding.UTF8.GetBytes(sum);
stream.Write(bytes.ToArray());
}
Console.WriteLine(await await a + await await b);
}
}
}
P.S 如果您想知道为什么我使用 List<dynamic>
来存储 TaskCompletionSource
-s ,那是因为 TransactionOperations 会不同之处在于 return type.Some 其中 return int
,其他 String
..Bool
..etc.
为了更好地理解我做了一个模式-
如您所见,有:
-我要存储 TCS-es 的列表
-一些只有在外部触发器被设置后才完成的调用(交易被执行)
正如您在 Calls
中所见,它们都有不同的 return 类型。
为什么需要 Task<Task<int>>
?简单地 Task<int>
就足够了,因此 TaskCompletionSource<int>
。而且您还摆脱了尴尬的 await await ...
,这在您的情况下也不是必需的。
请注意,我还向 File.Create()
返回的流中添加了 Close()
。
这是该程序的工作版本:
class Program
{
public static Task<int> TransactionOperation1()
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tasks.Add(tcs);
return tcs.Task;
}
public static Task<int> TransactionOperation2()
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tasks.Add(tcs);
return tcs.Task;
}
public static async Task<int> ExecuteTransactionOnDB()
{
await Task.Delay(1000);
return 5;
}
public static async Task TriggerTransaction()
{
int value = await ExecuteTransactionOnDB();
foreach (var item in tasks)
{
item.SetResult(value);
}
}
public static List<dynamic> tasks = new List<dynamic>();
static async Task Main(string[] args)
{
Task<int> a = TransactionOperation1();
Task<int> b = TransactionOperation2();
Task input = Task.Run(async () => {
while (Console.ReadKey().Key != ConsoleKey.A);
await TriggerTransaction();
});
if (!File.Exists("C:\temp\data.txt"))
{
File.Create("C:\temp\data.txt").Close();
}
using (FileStream stream = new FileStream("C:\temp\data.txt", FileMode.Append, FileAccess.Write))
{
int sum = await a + await b; // now it works ok
var bytes = Encoding.UTF8.GetBytes(sum.ToString());
stream.Write(bytes);
}
Console.WriteLine(await a + await b);
}
}
检查代码的修改版本,通过执行使用 TaskCompletionSource
创建的 Task
,它产生了预期的结果。我也将代码设为通用,这样您就不需要使用 dynamic
类型并在编译时定义数据类型
static async Task Main(string[] args)
{
var a = Program<int>.TransactionOperation1();
var b = Program<int>.TransactionOperation2();
await Task.Run(async() =>
{
Console.ReadLine();
await Program<int>.TriggerTransaction(5);
});
if (!File.Exists("D:\data.txt"))
{
File.Create("D:\data.txt");
}
using (FileStream stream = new FileStream("D:\data.txt", FileMode.Append, FileAccess.Write))
{
int sum = await a + await b;//thread wont pass this line when tasks are set.
var bytes = Encoding.UTF8.GetBytes(sum.ToString());
stream.Write(bytes, 0, bytes.Length);
}
Console.WriteLine(await a + await b);
}
class Program<T>
{
public static Task<T> TransactionOperation1()
{
var tcs = new TaskCompletionSource<T>();
tasks.Add(tcs);
return tcs.Task;
}
public static Task<T> TransactionOperation2()
{
var tcs = new TaskCompletionSource<T>();
tasks.Add(tcs);
return tcs.Task;
}
public static async Task<T> ExecuteTransactionOnDB(T t)
{
return await Task.FromResult(t);
}
public static async Task TriggerTransaction(T t)
{
T value = await ExecuteTransactionOnDB(t);
foreach (var item in tasks)
{
item.SetResult(value);
}
}
public static List<TaskCompletionSource<T>> tasks = new List<TaskCompletionSource<T>>();
}
以下是重要的修改:
List<dynamic>
替换为 List<TaskCompletionSource<T>>
TransactionOperation1/2
有 return 类型 Task<T>
,这是使用 TaskCompletionSource<T>
创建的任务
向 Task.Run
添加了一个额外的 await,它在内部执行 TriggerTransaction
,但您可以替换以下代码:
await Task.Run(async() =>
{
Console.ReadLine();
await Program<int>.TriggerTransaction(5);
});
与
await Program<int>.TriggerTransaction(5);
现在它产生了你期望的结果,它将把两个整数相加。一些小的更改,例如删除 Task.Delay
,这不是必需的
编辑 1 - 使用 Task.WhenAll
static async Task Main(string[] args)
{
var a = Program.TransactionOperation1(5);
var b = Program.TransactionOperation1(5);
Console.ReadLine();
var taskResults = await Task.WhenAll(a,b);
dynamic finalResult = 0;
foreach(var t in taskResults)
finalResult += t;
if (!File.Exists("D:\data.txt"))
{
File.Create("D:\data.txt");
}
using (FileStream stream = new FileStream("D:\data.txt", FileMode.Append, FileAccess.Write))
{
var bytes = Encoding.UTF8.GetBytes(finalResult.ToString());
stream.Write(bytes, 0, bytes.Length);
}
Console.WriteLine(finalResult);
}
class Program
{
public static Task<dynamic> TransactionOperation1(dynamic val)
{
return Task<dynamic>.Run(() => val);
}
public static Task<dynamic> TransactionOperation2(dynamic val)
{
return Task<dynamic>.Run(() => val);
}
}
您好,我遇到了以下问题:
我想执行类似于事务的操作。我想在收到外部 trigger.Therefore 后执行一些 async
操作 我正在使用 TaskCompletionSource
,它在表示触发器的方法中设置:TriggerTransaction
.
当我按下特定的控制台键时,此触发方法在 Main
线程池中被调用。
在我按下 A
关键字后,TriggerTransaction
被执行并且 TaskCompletionSource
-s 得到 set.Still 主线程不计算等待的两个总和任务。
class Program
{
public static Task<Task<int>> TransactionOperation1()
{
TaskCompletionSource<Task<int>> tcs = new TaskCompletionSource<Task<int>>();
tasks.Add(tcs);
Task<Task<int>> result = tcs.Task;
return result;
}
public static Task<Task<int>> TransactionOperation2()
{
TaskCompletionSource<Task<int>> tcs = new TaskCompletionSource<Task<int>>();
tasks.Add(tcs);
Task<Task<int>> result = tcs.Task;
return result;
}
public static async Task<int> ExecuteTransactionOnDB()
{
await Task.Delay(1000);
return 5;
}
public static async Task TriggerTransaction()
{
int value = await ExecuteTransactionOnDB();
foreach (var item in tasks)
{
item.SetResult(value);
}
}
public static List<dynamic> tasks = new List<dynamic>();
static async Task Main(string[] args)
{
Task<Task<int>> a = TransactionOperation1();
Task<Task<int>> b = TransactionOperation2();
Task.Run(async() =>
{
while (Console.ReadKey().Key != ConsoleKey.A) ;
await TriggerTransaction();
});
if (!File.Exists("D:\data.txt"))
{
File.Create("D:\data.txt");
}
using(FileStream stream=new FileStream("data.txt",FileMode.Append,FileAccess.Write))
{
int sum=await await a + await await b;//thread wont pass this line when tasks are set.
ReadOnlyMemory<byte> bytes = Encoding.UTF8.GetBytes(sum);
stream.Write(bytes.ToArray());
}
Console.WriteLine(await await a + await await b);
}
}
}
P.S 如果您想知道为什么我使用 List<dynamic>
来存储 TaskCompletionSource
-s ,那是因为 TransactionOperations 会不同之处在于 return type.Some 其中 return int
,其他 String
..Bool
..etc.
为了更好地理解我做了一个模式-
如您所见,有:
-我要存储 TCS-es 的列表
-一些只有在外部触发器被设置后才完成的调用(交易被执行)
正如您在 Calls
中所见,它们都有不同的 return 类型。
为什么需要 Task<Task<int>>
?简单地 Task<int>
就足够了,因此 TaskCompletionSource<int>
。而且您还摆脱了尴尬的 await await ...
,这在您的情况下也不是必需的。
请注意,我还向 File.Create()
返回的流中添加了 Close()
。
这是该程序的工作版本:
class Program
{
public static Task<int> TransactionOperation1()
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tasks.Add(tcs);
return tcs.Task;
}
public static Task<int> TransactionOperation2()
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tasks.Add(tcs);
return tcs.Task;
}
public static async Task<int> ExecuteTransactionOnDB()
{
await Task.Delay(1000);
return 5;
}
public static async Task TriggerTransaction()
{
int value = await ExecuteTransactionOnDB();
foreach (var item in tasks)
{
item.SetResult(value);
}
}
public static List<dynamic> tasks = new List<dynamic>();
static async Task Main(string[] args)
{
Task<int> a = TransactionOperation1();
Task<int> b = TransactionOperation2();
Task input = Task.Run(async () => {
while (Console.ReadKey().Key != ConsoleKey.A);
await TriggerTransaction();
});
if (!File.Exists("C:\temp\data.txt"))
{
File.Create("C:\temp\data.txt").Close();
}
using (FileStream stream = new FileStream("C:\temp\data.txt", FileMode.Append, FileAccess.Write))
{
int sum = await a + await b; // now it works ok
var bytes = Encoding.UTF8.GetBytes(sum.ToString());
stream.Write(bytes);
}
Console.WriteLine(await a + await b);
}
}
检查代码的修改版本,通过执行使用 TaskCompletionSource
创建的 Task
,它产生了预期的结果。我也将代码设为通用,这样您就不需要使用 dynamic
类型并在编译时定义数据类型
static async Task Main(string[] args)
{
var a = Program<int>.TransactionOperation1();
var b = Program<int>.TransactionOperation2();
await Task.Run(async() =>
{
Console.ReadLine();
await Program<int>.TriggerTransaction(5);
});
if (!File.Exists("D:\data.txt"))
{
File.Create("D:\data.txt");
}
using (FileStream stream = new FileStream("D:\data.txt", FileMode.Append, FileAccess.Write))
{
int sum = await a + await b;//thread wont pass this line when tasks are set.
var bytes = Encoding.UTF8.GetBytes(sum.ToString());
stream.Write(bytes, 0, bytes.Length);
}
Console.WriteLine(await a + await b);
}
class Program<T>
{
public static Task<T> TransactionOperation1()
{
var tcs = new TaskCompletionSource<T>();
tasks.Add(tcs);
return tcs.Task;
}
public static Task<T> TransactionOperation2()
{
var tcs = new TaskCompletionSource<T>();
tasks.Add(tcs);
return tcs.Task;
}
public static async Task<T> ExecuteTransactionOnDB(T t)
{
return await Task.FromResult(t);
}
public static async Task TriggerTransaction(T t)
{
T value = await ExecuteTransactionOnDB(t);
foreach (var item in tasks)
{
item.SetResult(value);
}
}
public static List<TaskCompletionSource<T>> tasks = new List<TaskCompletionSource<T>>();
}
以下是重要的修改:
List<dynamic>
替换为List<TaskCompletionSource<T>>
TransactionOperation1/2
有 return 类型Task<T>
,这是使用TaskCompletionSource<T>
创建的任务
向
Task.Run
添加了一个额外的 await,它在内部执行TriggerTransaction
,但您可以替换以下代码:await Task.Run(async() => { Console.ReadLine(); await Program<int>.TriggerTransaction(5); });
与
await Program<int>.TriggerTransaction(5);
现在它产生了你期望的结果,它将把两个整数相加。一些小的更改,例如删除 Task.Delay
,这不是必需的
编辑 1 - 使用 Task.WhenAll
static async Task Main(string[] args)
{
var a = Program.TransactionOperation1(5);
var b = Program.TransactionOperation1(5);
Console.ReadLine();
var taskResults = await Task.WhenAll(a,b);
dynamic finalResult = 0;
foreach(var t in taskResults)
finalResult += t;
if (!File.Exists("D:\data.txt"))
{
File.Create("D:\data.txt");
}
using (FileStream stream = new FileStream("D:\data.txt", FileMode.Append, FileAccess.Write))
{
var bytes = Encoding.UTF8.GetBytes(finalResult.ToString());
stream.Write(bytes, 0, bytes.Length);
}
Console.WriteLine(finalResult);
}
class Program
{
public static Task<dynamic> TransactionOperation1(dynamic val)
{
return Task<dynamic>.Run(() => val);
}
public static Task<dynamic> TransactionOperation2(dynamic val)
{
return Task<dynamic>.Run(() => val);
}
}