Ass*_*ast 3 c# mysql asynchronous
我在服务器中有一个数据库,似乎async方法不起作用.
这是我的代码:
static async void Example()
{
string connectionString =
"Server=mydomainname.com;" +
"Port=3306;" +
"Database=scratch;" +
"Uid=Assassinbeast;" +
"Password=mypass123;" +
"AllowUserVariables= true;";
MySql.Data.MySqlClient.MySqlConnection sqConnection = new MySql.Data.MySqlClient.MySqlConnection(connectionString);
await sqConnection.OpenAsync();
Console.Write("Opened. Now Click to close");
Console.ReadLine();
sqConnection.Close();
}
static void Main(string[] args)
{
Console.ReadLine();
Example();
Console.WriteLine("Done");
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
在"await"语句中,它实际上应该跳回Main()函数并写出"Done".但它不这样做.它只是同步运行,就像它不是异步方法一样,一旦功能完全完成,它将首先写入"完成".
那我做错了什么?这是一个错误吗?
UPDATE
好的,所以在我得到一些答案之后,我实际上仍然看不到OpenAsync()和Open()之间的任何区别.
我开始尝试测试更多的东西,我想我可以得出结论,异步方法不起作用
这是我的新代码:
static async Task Example()
{
string connectionString =
"Server=mydomainname.com;" +
"Port=3306;" +
"Database=scratch;" +
"Uid=Assassinbeast;" +
"Password=mypass123;" +
"AllowUserVariables= true;";
using (var sqConnection = new MySql.Data.MySqlClient.MySqlConnection(connectionString))
{
Console.WriteLine("Opening");
await sqConnection.OpenAsync();
Console.WriteLine("Opened. Now Closing");
}
}
static async Task Example2()
{
//Lets pretend this is a database that my computer will try to connect to
Console.WriteLine("Opening");
await Task.Delay(1000); //Lets say it takes 1 second to open
Console.WriteLine("Opened. Now Closing");
}
static void Main(string[] args)
{
Console.ReadLine();
Task.Run(() => Example());
Task.Run(() => Example());
Task.Run(() => Example());
Task.Run(() => Example());
Task.Run(() => Example());
Task.Run(() => Console.WriteLine("Done"));
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
这里当我运行Example()5次时,它将输出如下:

它需要3秒才会写出"完成".请注意,我的计算机根本不在CPU上工作,因为它只等待并连接到数据库,大约需要1秒才能连接到.
所以它实际上阻止了我的计算机线程并且没有运行多线程,否则它会立即写出"完成".
所以如果我调用Example2()而不是Example(),那么我得到的结果就是我想要的和我期望的结果:

在这里,它是真正的异步方法,因为我可以在我的计算机上一次完成6件事,只有2个核心.但是第一个例子,我一次只能做两件事,因为MySQL异步方法不起作用.
我还使用sqConnection.Open()测试了它,它与sqConnection.OpenAsync()具有完全相同的结果
所以现在,我只是想弄清楚如何同时连接数据库5次.
从一些旧代码(6.7.2)来看,似乎mysql ADO.NET提供程序没有正确实现任何异步功能.这包括TAP模式和旧样式Begin ...,End ...异步模式.在该版本中,Db*异步方法似乎根本没有写入; 他们将使用.NET中的基类,它们是同步的,看起来像是:
public virtual Task<int> ExecuteNonQueryAsync(...) {
return Task.FromResult(ExecuteNonQuery(...));
}
Run Code Online (Sandbox Code Playgroud)
(与在任务中包装它的额外开销100%同步; 参考源在这里)
如果Begin和End版本写得正确(它们不是),它可以实现如下:
public override Task<int> ExecuteNonQueryAsync(...) {
return Task<int>.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null);
}
Run Code Online (Sandbox Code Playgroud)
这样做取决于底层套接字的某种回调api最终以一种模式处理,其中调用者通过套接字发送一些字节,然后注册的方法在准备就绪时从底层网络堆栈回调.
但是,mysql连接器不会这样做(它首先不会覆盖该方法;但如果确实如此,相关的开始和结束方法在某些底层套接字api上不是异步的).什么MySQL的连接器做代替是建立一个代表对当前的连接实例的内部的方法和同步调用它在一个单独的线程.你不能同时在同一个连接上执行第二个命令,例如:
private static void Main() {
var sw = new Stopwatch();
sw.Start();
Task.WaitAll(
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync());
sw.Stop();
Console.WriteLine(sw.Elapsed.Seconds);
}
private static DbCommand GetDelayCommand() {
var connection = new MySqlConnection (...);
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = "SLEEP(5)";
cmd.CommandType = CommandType.Text;
return cmd;
}
Run Code Online (Sandbox Code Playgroud)
(假设您是连接池,并且任务数量超过最大池大小;如果异步工作,则此代码将获得一个数字,具体取决于池中的连接数而不是数字,具体取决于该数量和可以并发运行的线程)
这是因为代码锁定了驱动程序(管理网络内部的实际内容;*).如果它没有(并且内部是其他线程安全的,而其他方式用于管理连接池),它继续在底层网络流上执行阻塞调用.
所以是的,这个代码库没有异步支持.如果有人能指出我的代码,我可以看一个更新的驱动程序,但我怀疑NetworkStream基于内部的对象看起来并没有显着不同,异步代码也没有太大的不同.一个async配套的驱动程序必须写得最多的依赖于这样做的异步方式,并有同步码的同步封装的内部的; 或者它看起来更像是SqlClient参考源,并依赖于一些Task包装库来抽象出同步或异步运行之间的差异.
*锁定驱动程序并不意味着它不可能使用非阻塞IO,只是该方法无法使用lock语句编写并使用IAsyncResult之前已编写的非阻塞开始/结束代码TAP模式.
编辑:下载6.9.8; 怀疑没有正常的异步代码(非阻塞IO操作); 这里有一个错误:https://bugs.mysql.com/bug.php?id = 70111
2016年7月6日更新:关于GitHub的有趣项目,可能最终在https://github.com/mysql-net/MySqlConnector上解决这个问题(可能会使用更多与其成功有关的贡献者[我不再处理任何与MySQL的]).
嗯,可能有一个已打开的池连接。在这种情况下,它会同步返回给您。
需要注意的是,await不一定将控制权返回给调用方法。仅当正在等待的任务的状态为 时,它才返回调用方法TaskStatus.Running。如果任务已完成,则执行将正常进行。
尝试等待此方法,该方法返回状态为 的任务RanToCompletion:
public Task<int> SampleMethod()
{
return Task.FromResult(0);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4406 次 |
| 最近记录: |