为什么.Net没有Thread.Start()的通用版本?

3

我想知道为什么.Net没有一个通用的方法来启动线程。

例如,我们可以按照以下方式启动线程....

Thread th = new Thread(SayHello);
th.Start("Hello");

private static void SayHello(object obj)
        {
            string str = obj as string;
            Console.WriteLine(str);
        }

为什么我们不能拥有泛型的.NET?.NET团队为什么没有考虑过这个问题呢?下面是一个类似的例子...
Thread<string> th = new Thread<string>(SayHello);

因为很多时候,当我将值类型传递给线程开始时,我必须进行装箱/拆箱操作。

你可以轻松地自己添加这样的封装类。(此外,这个特定的例子不是装箱/拆箱,而是引用向下转换。) - Paul Ruane
4
你好,感兴趣想问一下,相比于启动新线程或在线程之间切换上下文,你认为装箱/拆箱会带来多大的性能损失? - Daniel Kelley
4
默认情况下未实现功能特性默认是未实现的。程序员要意识到他们需要明确地实现和测试每个特性。这有助于避免在代码中留下错误或不完整的特性,同时也能让开发者更好地理解系统的工作方式。因此,对于任何特性,在开始时应该将其视为未实现,并提醒自己在代码中明确实现它。 - Habib
6个回答

4
我能看出为什么实现BCL的人们不费力地写出这样的东西的几个原因:
  1. 如果您担心性能问题,那么转换(即使是拆箱转换)对于创建线程来说将是一个更小的损失。
  2. 如果您担心类型安全,您可以使用lambda表达式:new Thread(() => SayHello("Hello"))
  3. Thread<T>会让人感到困惑,因为不清楚T代表什么。特别是它的意义与Task<T>中的T完全不同。
  4. 如果您愿意,可以使用20行代码创建Thread<T>的包装器(见下文)。
所以,这个问题微不足道,如果它真的困扰到您并且解决方案会令人困惑,那么它很容易被解决。这很可能是为什么没有投入资源来实现它的原因。
Thread<T>的可能实现方式:
class Thread<T>
{
    private readonly Action<T> m_action;
    private readonly Thread m_thread;
    private T m_parameter;

    public Thread(Action<T> action)
    {
        m_action = action;
        m_thread = new Thread(DoWork);
    }

    public void Start(T parameter)
    {
        m_parameter = parameter;
        m_thread.Start();
    }

    private void DoWork()
    {
        m_action(m_parameter);
    }
}

2

使用lambda表达式启动线程非常容易,可以使用强类型,因此不需要添加任何新的语言支持。

例如:

using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        // Easy way to start a thread with strongly-typed multiple parameters:

        new Thread(() => MyThreadFunc("Test", 42, DateTime.Now)).Start();

        Console.WriteLine("Started thread.");
        Thread.Sleep(2000);
    }

    static void MyThreadFunc(string param1, int param2, DateTime param3)
    {
        Thread.Sleep(1000);
        Console.WriteLine("param1 = {0}, param2 = {1}, param3 = {2}", param1, param2, param3);
    }
}

2

因为还没有人编写这个方法。此外,由于这里的装箱/拆箱只是整个操作的相对较小的部分 而且 很少有程序员实际上需要手动启动线程(对于大多数用例来说有更好的抽象),他们可能认为没有必要指定、实现、测试和记录一个实际上不需要的更改。


1

在.NET中有很多类,如果它们是在泛型引入后设计的话,我想它们都会有一个通用版本。Thread只是其中之一。

对于这个特定的问题,如果您可以使用.NET 4.0+:

请使用System.Threading.Tasks命名空间中的Task类。

private static void SayHello(string s)
{
    Task t = new Task(() => Console.WriteLine(s));
    t.Start();
}

这个例子是类型安全的,和你的例子一样有效。方法不同,如果你期望有一个结果,Task确实更有意义,但仍然是一个很好的替代品,即使在这里也是如此。我猜微软不会再投入"旧"的Thread类,但可能会继续改进任务并行库

虽然我通常会同意使用Task而不是Thread,但它对解决这个特定的问题没有任何帮助。 - svick
你能解释一下在这种情况下如何使用“Task”吗?因为我真的不认为它会有帮助。 - svick
Task类并不是Thread的替代品。任务应该是短暂的,而不是用于连续操作。你应该提到这一点。 - JustAnotherUserYouMayKnow
3
这就是“TaskCreationOptions.LongRunning”的作用。 - svick
在你的新示例中,你可以将 Task 替换为 Thread,它仍然能够工作。这是使用 lambda 表达式的原因,但不是使用 Task 的原因。TaskThread 更好的理由有很多,但这不是其中之一。 - svick
正如我在一次编辑中所说,如果您期望有一个结果的话,使用Task会更加合理。一开始,我将Task<T>中的T误解为参数类型而非结果类型。因此,在这种情况下,您是正确的。我仍然不明白为什么还要使用Thread而不是Task。 - Jobo

0
由于“历史原因”,该方法是在.NET 1中创建的(没有泛型),并且在之后没有修复。与ICloneable等情况相同。

但是 Task 是在 .Net 4.0 中创建的,使用了泛型,并且仍然存在这个问题(http://msdn.microsoft.com/en-us/library/dd321456.aspx)。 - svick
是的,但现在使用lambda很容易,所以实现任意数量的类型参数没有真正的好处 - 它们只会很难使用,代码看起来很糟糕。 - Matthew Watson

0

奇怪。。。实际上没有人问过为什么有人想要做 OP 正在问的事情。线程(thread)是设计来运行一段代码的,不是一种方法。由于.NET中泛型的本质,代码 new Thread() 将意味着创建一个具有特定类型-字符串(string)的对象。这与Thread类的目的无关,即运行一段时间并执行某些复杂操作。

为了说明我的想法-这就像他问为什么我们没有配备电视和XBOX的蒸汽压路机一样...

总的来说,我的答案是 - 这不是因为他们没有费心去实现而没有实现,而是因为它与.NET的架构相矛盾..也就是说 *错误的*。


我真的不明白你在说什么。线程运行一段代码,而那段代码是一个方法。该方法可以接受输入,但必须是“对象”,但不能限定为某种特定类型。 - svick
同时,从泛型的本质来看,new Thread<string>() 意味着创建一个与 string 有关系的对象,但它并没有说明这种关系是什么。为什么不能是“这是一个运行需要 string 输入的代码的 Thread ”? - svick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接