使用 Task.Run 无需等待的异步任务和数据收集
Async tasks and data collections using Task.Run without waiting
在 WCF 服务中,我正在向其他 API/Libraries 发送多个请求,我不想等待这些任务完成,所以我最终使用 Task.Run 来完成异步任务 无需等待完成.
代码如下所示:
var someList = new List<int>();
var i = 0;
foreach (var item in group)
{
i++;
var variableOne = i;
Task.Run(async () =>
{
// Does the **variableOne** and variable **i** equals the latest value assigned to it, or the value at the time of calling?**
// Can someList be prematurely garbage collected before the tasks run, because the original function containing all the code shown in the example has completed (since Task.Run is not awaited)?
await OcrUtility.ApiOcrUpload(
new OcrUtility.ApiOcrUploadContract()
{
documentList = item.Documents
});
});
}
我的三个问题是:
- 是否可以在任务内容 运行 之前过早地 disposed/garbage 收集 someList(或任务内容引用的任何其他对象)?
- 任务中的变量i是最新赋给它的值,还是调用时的值?
- 我习惯了 Javascript,我知道如果我在 javascript 中使用
setTimeout()
我需要使用某种 context-copy 技巧是为了在调用时保持 variableOne
的当前值,因此当 "task" (函数在 JS 的情况下)正在执行。
我们是否需要使用 C# 进行这种复制,或者它是否带有内置的上下文复制? .Net 是否评估正在使用的变量,并在调用时创建它们的副本?
List<T>
不是一次性的,所以不,不能丢弃。如果您的意思是垃圾收集,那么如果您可以通过托管代码访问它们,则不会收集任何对象;这只是在处理 unsafe
代码时需要考虑的事情。
它是变量在当前时间点的值,不是关闭时变量的值。闭包关闭 variables,而不是 values.
这里的行为是一样的;闭包关闭变量,而不是值。这就是为什么您需要在 lambda 中创建 variableOne
而不是使用 i
的原因。如果您关闭 i
,您将获得 i
的当前值,但是当您在 内部 循环中获取该值的副本时,永远不会改变该变量 (variableOne
),关闭时变量的值始终与调用委托时变量的值相同。
您当然可以使用以下代码对此进行简单测试:
int i = 3;
Func<int> f = () => i;
i = 42;
Console.WriteLine(f());
如果它打印 3
,则意味着闭包关闭超过 值 。如果它打印 42
那么它告诉你闭包关闭 variables.
WCF 允许您创建 one-way services,其中客户端不等待响应,因此它不会超时。
简而言之,您将 IsOneWay property of your method's OperationalContract 属性设置为 true
。文档中的以下片段演示了这一点:
[ServiceContract]
public class OneAndTwoWay
{
// The client waits until a response message appears.
[OperationContract]
public int MethodOne (int x, out int y)
{
y = 34;
return 0;
}
// The client waits until an empty response message appears.
[OperationContract]
public void MethodTwo (int x)
{
return;
}
// The client returns as soon as an outbound message
// is queued for dispatch to the service; no response
// message is generated or sent.
[OperationContract(IsOneWay=true)]
public void MethodThree (int x)
{
return;
}
}
在 WCF 服务中,我正在向其他 API/Libraries 发送多个请求,我不想等待这些任务完成,所以我最终使用 Task.Run 来完成异步任务 无需等待完成.
代码如下所示:
var someList = new List<int>();
var i = 0;
foreach (var item in group)
{
i++;
var variableOne = i;
Task.Run(async () =>
{
// Does the **variableOne** and variable **i** equals the latest value assigned to it, or the value at the time of calling?**
// Can someList be prematurely garbage collected before the tasks run, because the original function containing all the code shown in the example has completed (since Task.Run is not awaited)?
await OcrUtility.ApiOcrUpload(
new OcrUtility.ApiOcrUploadContract()
{
documentList = item.Documents
});
});
}
我的三个问题是:
- 是否可以在任务内容 运行 之前过早地 disposed/garbage 收集 someList(或任务内容引用的任何其他对象)?
- 任务中的变量i是最新赋给它的值,还是调用时的值?
- 我习惯了 Javascript,我知道如果我在 javascript 中使用
setTimeout()
我需要使用某种 context-copy 技巧是为了在调用时保持variableOne
的当前值,因此当 "task" (函数在 JS 的情况下)正在执行。 我们是否需要使用 C# 进行这种复制,或者它是否带有内置的上下文复制? .Net 是否评估正在使用的变量,并在调用时创建它们的副本?
List<T>
不是一次性的,所以不,不能丢弃。如果您的意思是垃圾收集,那么如果您可以通过托管代码访问它们,则不会收集任何对象;这只是在处理unsafe
代码时需要考虑的事情。它是变量在当前时间点的值,不是关闭时变量的值。闭包关闭 variables,而不是 values.
这里的行为是一样的;闭包关闭变量,而不是值。这就是为什么您需要在 lambda 中创建
variableOne
而不是使用i
的原因。如果您关闭i
,您将获得i
的当前值,但是当您在 内部 循环中获取该值的副本时,永远不会改变该变量 (variableOne
),关闭时变量的值始终与调用委托时变量的值相同。
您当然可以使用以下代码对此进行简单测试:
int i = 3;
Func<int> f = () => i;
i = 42;
Console.WriteLine(f());
如果它打印 3
,则意味着闭包关闭超过 值 。如果它打印 42
那么它告诉你闭包关闭 variables.
WCF 允许您创建 one-way services,其中客户端不等待响应,因此它不会超时。
简而言之,您将 IsOneWay property of your method's OperationalContract 属性设置为 true
。文档中的以下片段演示了这一点:
[ServiceContract]
public class OneAndTwoWay
{
// The client waits until a response message appears.
[OperationContract]
public int MethodOne (int x, out int y)
{
y = 34;
return 0;
}
// The client waits until an empty response message appears.
[OperationContract]
public void MethodTwo (int x)
{
return;
}
// The client returns as soon as an outbound message
// is queued for dispatch to the service; no response
// message is generated or sent.
[OperationContract(IsOneWay=true)]
public void MethodThree (int x)
{
return;
}
}