使用<form action="#" id="form" class="form-horizontal" onsubmit="save();">
<!-- Form stuff -->
<div class="modal-footer">
<input type="submit" id="btnSave" class="btn btn-primary" value="save">
<button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
</div>
</form>
时,如果我将阻止System.Threading.Tasks.Dataflow
与阻止a
相关联,链接会保持b
还活着吗?或者我是否需要保留对b
周围的引用以防止它被收集?
b
答案 0 :(得分:3)
您将变量与变量内容混淆。他们的生命周期可以完全不同。
一旦控件离开块,局部变量b
就不再是GC的根。存储在b
中的引用引用的对象是一个托管对象,GC至少只要它可以从根目录访问它就能保持活动状态。
现在,请注意,在控件离开块之前,允许GC将局部变量视为死。如果你有:
var a = whatever;
a.Foo();
var b = whatever;
// The object referred to by `a` could be collected here.
b.Foo();
return;
因为例如,抖动可能决定b
可以使用与a
相同的本地存储,因为它们的用法不会重叠。 只要a
在范围内,就不要求a
引用的对象保持活动状态。
如果对象具有带有副作用的析构函数,则需要延迟到块结束时,这可能会导致问题;当您在析构函数中进行非托管代码调用时,尤其会发生这种情况。在这种情况下,使用keep-alive来保持活着。
答案 1 :(得分:2)
除了@Eric对GC行为的重要解释之外,我想解决与TPL-Dataflow相关的特殊情况。您可以轻松地查看LinkTo
从简单测试中获得的行为。请注意,据我所知,除了b
的链接外,没有任何内容可以保留a
。
[TestFixture]
public class BlockTester
{
private int count;
[Test]
public async Task Test()
{
var inputBlock = BuildPipeline();
var max = 1000;
foreach (var input in Enumerable.Range(1, max))
{
inputBlock.Post(input);
}
inputBlock.Complete();
//No reference to block b
//so we can't await b completion
//instead we'll just wait a second since
//the block should finish nearly immediately
await Task.Delay(TimeSpan.FromSeconds(1));
Assert.AreEqual(max, count);
}
public ITargetBlock<int> BuildPipeline()
{
var a = new TransformBlock<int, int>(x => x);
var b = new ActionBlock<int>(x => count = x);
a.LinkTo(b, new DataflowLinkOptions() {PropagateCompletion = true});
return a;
}
}
答案 2 :(得分:1)
是的,链接一个数据流块足以防止对其进行垃圾回收。不仅如此,即使没有任何引用,仅通过工作即可完成工作,直到该块工作完成。这是一个runnable示例:
public static class Program
{
static void Main(string[] args)
{
StartBlock();
Thread.Sleep(500);
for (int i = 5; i > 0; i--)
{
Console.WriteLine($"Countdown: {i}");
Thread.Sleep(1000);
GC.Collect();
}
Console.WriteLine("Shutting down");
}
static void StartBlock()
{
var block = new ActionBlock<int>(item =>
{
Console.WriteLine("Processing an item");
Thread.Sleep(1000);
});
for (int i = 0; i < 10; i++) block.Post(i);
}
}
输出:
Processing an item
Countdown: 5
Processing an item
Countdown: 4
Processing an item
Countdown: 3
Processing an item
Countdown: 2
Processing an item
Countdown: 1
Processing an item
Shutting down
Press any key to continue . . .
只要该进程中还有一个前台线程,该块就会继续运行。