虽然有利于线程卫生,但我希望异步 I/O 总是比同步 I/O 慢一点。我的测试似乎证明异步 I/O 有时比同步更快。我在这里想念什么?
[编辑] 我最初的测量是错误的(我没有删除它们以不使所做的评论无效)。
以下是一些固定定时循环的测量结果: ADO_DataReaderSync 每次迭代=4,17ms ADO_DataReaderASyncReader 每次迭代=3,55ms(仅 ExecuteReaderAsync) ADO_DataReaderASyncRead 每次迭代=11,28ms(ExecuteReaderAsync 和 ReadAsync) FileIO_ReadToEndSync SmallFile 每次迭代=3,67ms FileIO_ReadToEndAsync SmallFile 每次迭代=8,97ms FileIO_ReadToEndSync LargeFile 每次迭代=266,34ms FileIO_ReadToEndAsync LargeFile 每次迭代=322,05ms
错误测量:
ADO_ReadSync elapsed:00:00:00.0012249 每次迭代=0,12249ms ADO_ReadAsync elapsed:00:00:00.0050702 每次迭代=0,50702ms ADO_DataReaderSync elapsed:00:00:00.0090513 每次迭代=0,90513ms ADO_DataReaderASync elapsed:00:00:00.0044125 每次迭代=0,44125ms FileIO_ReadSync LargeFile elapsed:00:00:00.0655596 每次迭代=6,55596ms FileIO_ReadAsync LargeFile elapsed:00:00:00.0003056 每次迭代=0,03056ms FileIO_ReadSync SmallFile elapsed:00:00:00.0005619 每次迭代=0,05619ms FileIO_ReadAsync SmallFile elapsed:00:00:00.0002955 每次迭代=0,02955ms
使用的测试代码:
Module Module1
Private Const _connectionString = "Data Source=zulu;Initial Catalog=AdventureWorks;Integrated Security=True"
Sub Main()
DoTimed("ADO_ReadSync", Sub() ADO_ScalarSync(), 10)
DoTimed("ADO_ReadAsync", Async Sub() Await ADO_ScalarAsync(), 10)
DoTimed("ADO_DataReaderSync", Sub() ADO_DataReaderSync(), 10)
DoTimed("ADO_DataReaderASync", Async Sub() Await ADO_DataReaderASync(), 10)
Const filePathLargeFile = "O:\Temp\TestFiles\In\todo.txt"
Const filePathSmallFile = "O:\Temp\TestFiles\In\eula.txt"
DoTimed("FileIO_ReadSync LargeFile", Sub() FileIO_ReadSync(filePathLargeFile), 10)
DoTimed("FileIO_ReadAsync LargeFile", Async Sub() Await FileIO_ReadAsync(filePathLargeFile), 10)
DoTimed("FileIO_ReadSync SmallFile", Sub() FileIO_ReadSync(filePathSmallFile), 10)
DoTimed("FileIO_ReadAsync SmallFile", Async Sub() Await FileIO_ReadAsync(filePathSmallFile), 10)
Console.WriteLine("...")
Console.ReadLine()
End Sub
Function ADO_ScalarSync() As Integer
Using cnx As New SqlClient.SqlConnection(_connectionString)
Dim cmd As New SqlCommand("SELECT COUNT(*) FROM Production.Product", cnx)
cnx.Open()
Return cmd.ExecuteScalar
End Using
End Function
Async Function ADO_ScalarAsync() As Task(Of Integer)
'Beginning in the .NET Framework 4.5 RC, these methods no longer require Asynchronous Processing=true in the connection string
Using cnx As New SqlClient.SqlConnection(_connectionString)
Dim cmd As New SqlCommand("SELECT COUNT(*) FROM Production.Product", cnx)
cnx.Open()
Return Await cmd.ExecuteScalarAsync
End Using
End Function
Function ADO_DataReaderSync() As List(Of String)
Using cnx As New SqlClient.SqlConnection(_connectionString)
Dim cmd As New SqlCommand("SELECT * FROM Production.Product", cnx)
cnx.Open()
Using rdr As SqlDataReader = cmd.ExecuteReader
Dim productNames As New List(Of String)
While rdr.Read
productNames.Add(rdr("Name"))
End While
Return productNames
End Using
End Using
End Function
Async Function ADO_DataReaderASync() As Task(Of List(Of String))
Using cnx As New SqlClient.SqlConnection(_connectionString)
'Await cnx.OpenAsync() 'I would only use .OpenAsync if the DB is commonly down and we would hang on the timeout
Dim cmd As New SqlCommand("SELECT * FROM Production.Product", cnx)
cnx.Open()
Using rdr As SqlDataReader = Await cmd.ExecuteReaderAsync
Dim productNames As New List(Of String)
While rdr.Read
productNames.Add(rdr("Name"))
End While
Return productNames
End Using
End Using
End Function
Function FileIO_ReadSync(filePath As String) As Long
Using reader As New StreamReader(filePath)
Dim fileString = reader.ReadToEnd
Return fileString.Length
End Using
End Function
Async Function FileIO_ReadAsync(filePath As String) As Task(Of Long)
Using reader As New StreamReader(filePath)
Dim fileString = Await reader.ReadToEndAsync().ConfigureAwait(False)
Return fileString.Length
End Using
End Function
端模块
Public Module Timing
Function DoTimed(name As String, operation As Action, Optional iterations As Integer = 1) As TimeSpan
operation() 'Warmup
Dim stw = Stopwatch.StartNew
DoIterate(operation, iterations)
stw.Stop()
Console.WriteLine("{0} elapsed:{1} per iteration={2}ms", name, stw.Elapsed, stw.Elapsed.TotalMilliseconds / iterations)
Return stw.Elapsed
End Function
Sub DoIterate(action As Action, Optional iterations As Integer = 1)
For i = 0 To iterations - 1
action()
Next
End Sub
端模块