实体框架和Process.Start阻止异步方法调用的执行


private void button1_Click(object sender, EventArgs e)
{
// Comment out the following line and the StartProcess Method works fine
List<SimpleTestTable> list = new PlainTestDBEntities().SimpleTestTables.ToList();
new Thread(StartProcess).Start();
while (true)
{ }
}
private void StartProcess()
{
Thread.Sleep(2000);
Console.WriteLine("I am executed totally fine.");
Process.Start("calc.exe");
Console.WriteLine("I am never executed if Entities are loaded in the calling method.");
}

由于某种原因,在给定的示例中,当从DB加载列表时,StartProcess方法将在调用Process.Start("calc.exe");之后挂起。所以计算器会出现,但随后执行停止。如果我注释掉DB加载行,一切都很好。

有什么想法吗?

谢谢。

更新:显然我对如何繁殖的说明不够清楚。我希望这将有所帮助:

  1. 运行以下脚本或手动执行该脚本,这将在SQL Server中创建一个名为PlainTestDB的数据库,并添加一个名称为SimpleTestTable的表,该表有两列。第一个ID上有bigint和primarykey标识,第二个Name nvarchar(50(,加上3个值A、B和C

重要信息:如果运行脚本,请确保CREATE DATABASE语句之后的go语句在下一行。

use master
go
CREATE DATABASE [PlainTestDB] CONTAINMENT = NONE ON PRIMARY ( NAME = N'PlainTestDB', FILENAME = N'C:DataPlainTestDB.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB ) LOG ON ( NAME = N'PlainTestDB_log', FILENAME = N'C:DataPlainTestDB_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB ) WITH CATALOG_COLLATION = DATABASE_DEFAULT 
GO
use [PlainTestDB]
CREATE TABLE [dbo].[SimpleTestTable]( [ID] [bigint] IDENTITY(1,1) NOT NULL, [Name] nvarchar NOT NULL, CONSTRAINT [PK_SimpleTestTable] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY]
USE [PlainTestDB]
INSERT INTO [dbo].[SimpleTestTable] ([Name]) VALUES ('A'),('B'),('C')
  1. 在Visual Studio中创建一个新的Windows窗体应用程序。并添加一个带有单击处理程序的按钮。

  2. 将ADO.NET实体数据模型添加到名为PlainTestDB的项目中。

  3. 从数据库中选择EF Designer。

  4. 将连接字符串添加到新创建的数据库中,并选中将其保存到应用程序配置的框。

  5. 选择实体框架6.x

  6. 选中表格复选框,然后单击完成

  7. 将上面的代码复制并粘贴到Form1.cs中。确保用粘贴的代码覆盖button1_Click方法。

  8. 添加以下使用语句

  9. 使用System.Threading;

  10. 使用System.Diagnostics;

  11. 在线路上放置断点

    Console.WriteLine("如果实体被加载到调用方法中,则我永远不会被执行。"(;

  12. 在调试模式下运行程序并点击按钮

  13. 您会注意到计算器打开了,但断点从未命中

  14. 一次评论一行,你会看到

  15. 注释掉数据库调用将解决挂起线程的问题

private void button1_Click(object sender, EventArgs e)
{
new Thread(BackgroundWorker).Start();
}
private void BackgroundWorker()
{
List<SimpleTestTable> list = new PlainTestDBEntities().SimpleTestTables.ToList();
new Thread(StartProcess).Start();
while (true)
{ 
// Wait for the external Process to complete its work.
}
}
private void StartProcess()
{
Thread.Sleep(2000);
Console.WriteLine("I am executed totally fine.");
Process.Start("calc.exe");
Console.WriteLine("I am now always executed because there is no UI handler interfering with Entity Framework and Process.Start");
}

这就解决了问题。在控制台应用程序中尝试了第一个示例后,我发现它运行得很好。因此,多亏了其中一条关于UI处理程序的友好评论中的提示,我想,UI处理程序必须首先完成它的工作,才能使所有线程正常运行。

但它仍然没有回答为什么会出现这种现象。为什么实体框架、点击处理程序和Process.Start在第一个例子中会相互阻塞?您可以很容易地进行测试,使用EntityFramework表设置一个简单的项目,如第一个示例中所述进行加载。只要删除实体框架代码,while((或Process.Start就可以工作。但并不是所有人都在一起。

很想知道,为什么会这样。

最新更新