1 回答

TA貢獻1712條經驗 獲得超3個贊
使用選項 1,您將向源發(fā)出許多請求以獲取數(shù)據(jù),并且GetBytes
不會在 SQL 服務器上“搜索”流(如果確實如此,我會感到驚訝),這將是一個非常低效的解決方案。
IAsyncEnumerable
使用選項 2,您可以獲得流并按需處理它,因此您將發(fā)出單個數(shù)據(jù)庫請求,并獲得異步 I/O 的所有好處。
使用C# 8
?IAsyncEnumerablePreview
將完美地解決您的問題,但到目前為止它還處于階段。
復制到異步
如果您可以獲得需要將內容上傳到的流,那么您可以使用CopyToAsync。但我假設每個塊都將在單獨的請求中上傳。如果是這樣,您可以引入一個組件,它會像 a 一樣發(fā)出嘎嘎聲,但當數(shù)據(jù)庫流在其上調用 CopyToAsync()Stream
時,它實際上會將內容上傳到網站:
class WebSiteChunkUploader : Stream
{
? ? ?private HttpClient _client = new HttpClient();
? ? ?public override bool CanWrite => true;
? ? ?public override bool CanRead => false;
? ? ?public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
? ? ? ? ?await _client.PostAsync("localhost", new ByteArrayContent(buffer,offset, count));
}
老好 IEnumerable
不幸的是你不能與yield return混合。但是,如果您決定使用阻塞 api 讀取流,例如,那么您可以使用舊的 good 重寫它:IEnumerableasync/awaitReadyield return
public IEnumerable<Tuple<byte[],int>> TransferDocument(int documentId, int maxChunkSize)
{
? ? string sql = "SELECT Data FROM Document WHERE Id = @Id";
? ? var buffer = new byte[maxChunkSize];
? ? using (SqlConnection connection = new SqlConnection(ConnectionString))
? ? {
? ? ? ? connection.Open();
? ? ? ? using (SqlCommand command = new SqlCommand(sql, connection))
? ? ? ? {
? ? ? ? ? ? command.Parameters.AddWithValue("@Id", documentId);
? ? ? ? ? ? using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
? ? ? ? ? ? using (Stream uploadDataStream = reader.GetStream(0))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? while(var bytesRead = uploadDataStream.Read(buffer, 0, maxChunkSize)) > 0)
? ? ? ? ? ? ? ? ? ?yield return Tuple(buffer, bytesRead);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
...
async Task DoMyTransfer()?
{
? foreach(var buffer in TransferDocument(1, 10000)) {
? ? await moveBytes(buffer)
? }
}
在這種情況下,您不會與 DB 和 fancy 進行異步 IO Tasks,但我想您無論如何都需要限制此上傳操作,以免連接導致數(shù)據(jù)庫過載。
- 1 回答
- 0 關注
- 128 瀏覽
添加回答
舉報