Task.Run() 访问方法范围变量是否安全?
Is it safe for Task.Run() to access Method scope variables?
以下是否保证打印“成功”,或者垃圾收集是否可能吃掉“dummyValue”对象,因为 TaskTest() 在它 returns 可以完成任务之前很久就结束了?
public class DummyValueClass
{
public string Value { get; private set; }
public DummyValueClass(string value)
{
Value = value;
}
}
public class ScopeTest
{
public Task<string> TaskTest()
{
var dummyValue = new DummyValueClass("Success");
return Task.Run(() =>
{
Thread.Sleep(10000);
return dummyValue?.Value;
});
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Beginning Test");
var scopeTester = new ScopeTest();
var task = scopeTester.TaskTest();
Console.WriteLine(task.Result);
}
}
是的,保证打印“成功”。因为当 lambda 捕获其范围外的值时,编译器将生成一个对象,该对象“捕获”从其范围外获取的变量。所以它不会被垃圾收集
这称为 闭包。
var dummyValue = new DummyValueClass("Success");
return Task.Run(() =>
{
Thread.Sleep(10000);
return dummyValue?.Value;
});
简而言之,编译器创建了一个编译器生成class并捕获dummyValue
作为实例成员。
清理后的代码示例。您可以查看所有详细信息 here
public class ScopeTest
{
[CompilerGenerated]
private sealed class GeneratedClass
{
public DummyValueClass dummyValue;
internal string InternalTaskTest()
{
Thread.Sleep(10000);
DummyValueClass dummyValueClass = dummyValue;
if (dummyValueClass == null)
{
return null;
}
return dummyValueClass.Value;
}
}
public Task<string> TaskTest()
{
GeneratedClass generatedClass = new GeneratedClass();
generatedClass.dummyValue = new DummyValueClass("Success");
return Task.Run(new Func<string>(generatedClass.InternalTaskTest));
}
}
任务现在有一个指向生成的方法的方法指针,它又是GeneratedClass
的根,它有一个参考你的DummyValueClass
。结果是 垃圾收集器 知道你的 reference 还活着。
以下是否保证打印“成功”,或者垃圾收集是否可能吃掉“dummyValue”对象,因为 TaskTest() 在它 returns 可以完成任务之前很久就结束了?
public class DummyValueClass
{
public string Value { get; private set; }
public DummyValueClass(string value)
{
Value = value;
}
}
public class ScopeTest
{
public Task<string> TaskTest()
{
var dummyValue = new DummyValueClass("Success");
return Task.Run(() =>
{
Thread.Sleep(10000);
return dummyValue?.Value;
});
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Beginning Test");
var scopeTester = new ScopeTest();
var task = scopeTester.TaskTest();
Console.WriteLine(task.Result);
}
}
是的,保证打印“成功”。因为当 lambda 捕获其范围外的值时,编译器将生成一个对象,该对象“捕获”从其范围外获取的变量。所以它不会被垃圾收集
这称为 闭包。
var dummyValue = new DummyValueClass("Success");
return Task.Run(() =>
{
Thread.Sleep(10000);
return dummyValue?.Value;
});
简而言之,编译器创建了一个编译器生成class并捕获dummyValue
作为实例成员。
清理后的代码示例。您可以查看所有详细信息 here
public class ScopeTest
{
[CompilerGenerated]
private sealed class GeneratedClass
{
public DummyValueClass dummyValue;
internal string InternalTaskTest()
{
Thread.Sleep(10000);
DummyValueClass dummyValueClass = dummyValue;
if (dummyValueClass == null)
{
return null;
}
return dummyValueClass.Value;
}
}
public Task<string> TaskTest()
{
GeneratedClass generatedClass = new GeneratedClass();
generatedClass.dummyValue = new DummyValueClass("Success");
return Task.Run(new Func<string>(generatedClass.InternalTaskTest));
}
}
任务现在有一个指向生成的方法的方法指针,它又是GeneratedClass
的根,它有一个参考你的DummyValueClass
。结果是 垃圾收集器 知道你的 reference 还活着。