需要帮助在C#中实现多线程

时间:2012-04-19 08:10:37

标签: c# .net multithreading

我正在创建一个应用程序,由于某种原因,当我点击按钮时,我必须启动一个新表单,同时在google文档中创建一个新文档。 我已经成功实现了上述功能,但是当应用程序忙于在谷歌文档中创建新文档时,新加载的表单的UI冻结了。 我在某处读到,如果我使用多线程,这可以避免。 所以现在我想问我应该创建两个线程,其中一个我应该放置代码来创建新表单,另一个我应该放置代码在google doc中创建一个文档。 或者我应该在线程上创建我应该放置代码来创建新的google doc并让新表单创建代码在主进程中? 另外,在已经编写的代码中实现线程的最简单方法是什么?如果可能的话,请提供一些参考阅读材料。

5 个答案:

答案 0 :(得分:6)

你实际上有很多选择。

(1) BackgroundWorker。如果你真的想要在WinForms中进行异步工作的最简单的编程模型,那就是这个。它通常用于执行一些异步任务并报告进度,但如果您不需要,则不必报告进度。

(2)基于事件的异步模式。如果你想制作一个完整的组件来执行某些异步任务,完全控制报告进度和你自己的自定义事件,那么这是一种方式去做吧。这也有助于您了解线程而不是BackgroundWorker。因为我是一个视觉人物,I created a full video presentation on how to do just this with WinForms

(3)任务并行库。您可以将TPL与WinForms一起使用,我写了very detailed blog post on how to do just that here

(4)异步和等待。请注意,这需要.NET 4.5,C#5.0和C#5.0编译器仅包含在Visual Studio 11中,Visual Studio 11现在仅在BETA中。 However, I also have a full blog post on how to do just this

(5)带有线程的ISynchronizedInvoke。这是另一个选项,I also have a full blog about

这取决于您选择哪种方法。我的建议是简要地看一下每个方法,然后选择一种方法,根据主题对你的感受,或者哪种方法最符合你的要求。

答案 1 :(得分:2)

您可以使用多种技术来完成您的要求,但我会建议使用任务并行库(TPL)(或BackgroundWorker)。

创建/启动新表单的开销很小(在大多数情况下),因此在我看来,您应该在UI线程上启动表单,并在后台线程上创建Google Doc。所以使用TPL你会有类似的东西(非常基本的例子)

// In click event.
MyForm newForm = new MyForm();
newForm.Show();

Task googleDocTask = Task.Factory.StartNew(() =>
{
    // Do your stuff with Google Docs.
    // Note you cannot access the UI thread from within this delegate.
});

有关C#中线程的精彩讨论,请参阅Joseph Albahari's page on threading

有关TPL的更多信息和相当完整的介绍,请参阅here

我希望这会有所帮助。

答案 2 :(得分:2)

只需创建一个线程。我建议使用BackgroundWorker。他们非常直接。

把它放在班级的顶端:

private BackgroundWorker googleDocWorker = new BackgroundWorker();

将它放在构造函数中:

googleDocWorker.DoWork += new DoWorkEventHandler(googleDocWorker_DoWork);
googleDocWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(googleDocWorker_RunWorkerCompleted);

将这些方法放在你的班级中:

void googleDocWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // You can use this to alert you that the google doc is created.
}

void googleDocWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Create google doc here.
}

调用此方法开始创建google doc:

googleDocWorker.RunWorkerAsync();

现在,如果您需要将一些数据传递给BackgroundWorker,您可以传递任何您想要的内容。您可以使用对象数组传入字符串,甚至是不同类型的多个对象。这是一个发送多个对象的示例:

googleDocWorker.RunWorkerAsync(new object[] { "doc name", contents });

现在,这意味着他们必须在_DoWork方法中处理:

void googleDocWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Create google doc here.
    object[] args = (object[])e.Argument;
    String docName = (string)args[0];
    SomeClass contents = (SomeClass)args[1];
}

假设您在创建文档后,想要将URL发送回刚刚创建的文档,您只需将其传递回_DoWork方法的_RunWorkerCompleted方法:

void googleDocWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Create google doc here.

    ...

    e.Result = myURL;
}

在RunWorkerCompleted方法中获取URL后,它与DoWork方法几乎相同。

void googleDocWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // You can use this to alert you that the google doc is created.
    String docURL = (String)e.Result;
}

希望有所帮助! (:

答案 3 :(得分:0)

IMHO。你应该只创建一个你将制作谷歌文档的线程(所以你将有两个线程)。

答案 4 :(得分:0)

最简单的方法是使用BackgroundWorker或使用ThreadPool。如果您的主UI在其他任务完成时并不在意,那么Threadpool会更简单。