FTP에서 Azure 대용량 파일로 대용량 파일을 더 빠르게 보낼 때 멀티 스레딩을 만드는 방법
Aug 19 2020
현재 FTP에서 로컬 하드 디스크로 파일을 다운로드하는 코드가 있습니다. 그런 다음 청크로 파일을 Azure에 업로드합니다. 마지막으로 로컬 및 ftp에서 파일을 삭제합니다. 이 코드는 매우 느립니다. 개선 방법을 알고 싶었습니다.
private async Task UploadToBlobJobAsync(FtpConfiguration ftpConfiguration, BlobStorageConfiguration blobStorageConfiguration, string fileExtension)
{
try
{
ftpConfiguration.FileExtension = fileExtension;
var filesToProcess = FileHelper.GetAllFileNames(ftpConfiguration).ToList();
var batchSize = 4;
List<Task> uploadBlobToStorageTasks = new List<Task>(batchSize);
for (int i = 0; i < filesToProcess.Count(); i += batchSize)
{
// calculated the remaining items to avoid an OutOfRangeException
batchSize = filesToProcess.Count() - i > batchSize ? batchSize : filesToProcess.Count() - i;
for (int j = i; j < i + batchSize; j++)
{
var fileName = filesToProcess[j];
var localFilePath = SaveFileToLocalAndGetLocation(ftpConfiguration, ftpConfiguration.FolderPath, fileName);
// Spin off a background task to process the file we just downloaded
uploadBlobToStorageTasks.Add(Task.Run(() =>
{
// Process the file
UploadFile(ftpConfiguration, blobStorageConfiguration, fileName, localFilePath).ConfigureAwait(false);
}));
}
Task.WaitAll(uploadBlobToStorageTasks.ToArray());
uploadBlobToStorageTasks.Clear();
}
}
catch (Exception ex)
{
}
}
private async Task UploadFile(FtpConfiguration ftpConfiguration, BlobStorageConfiguration blobStorageConfiguration, string fileName, string localFilePath)
{
try
{
await UploadLargeFiles(GetBlobStorageConfiguration(blobStorageConfiguration), fileName, localFilePath).ConfigureAwait(false);
FileHelper.DeleteFile(ftpConfiguration, fileName); // delete file from ftp
}
catch (Exception exception)
{
}
}
private async Task UploadLargeFiles(BlobStorageConfiguration blobStorageConfiguration, string fileName, string localFilePath)
{
try
{
var output = await UploadFileAsBlockBlob(localFilePath, blobStorageConfiguration).ConfigureAwait(false);
// delete the file from local
Logger.LogInformation($"Deleting {fileName} from the local folder. Path is {localFilePath}.");
if (File.Exists(localFilePath))
{
File.Delete(localFilePath);
}
}
catch (Exception ex)
{
}
}
private async Task UploadFileAsBlockBlob(string sourceFilePath, BlobStorageConfiguration blobStorageConfiguration)
{
string fileName = Path.GetFileName(sourceFilePath);
try
{
var storageAccount = CloudStorageAccount.Parse(blobStorageConfiguration.ConnectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var cloudContainer = blobClient.GetContainerReference(blobStorageConfiguration.Container);
await cloudContainer.CreateIfNotExistsAsync().ConfigureAwait(false);
var directory = cloudContainer.GetDirectoryReference(blobStorageConfiguration.Path);
var blob = directory.GetBlockBlobReference(fileName);
var blocklist = new HashSet<string>();
byte[] bytes = File.ReadAllBytes(sourceFilePath);
const long pageSizeInBytes = 10485760 * 20; // 20mb at a time
long prevLastByte = 0;
long bytesRemain = bytes.Length;
do
{
long bytesToCopy = Math.Min(bytesRemain, pageSizeInBytes);
byte[] bytesToSend = new byte[bytesToCopy];
Array.Copy(bytes, prevLastByte, bytesToSend, 0, bytesToCopy);
prevLastByte += bytesToCopy;
bytesRemain -= bytesToCopy;
// create blockId
string blockId = Guid.NewGuid().ToString();
string base64BlockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(blockId));
await blob.PutBlockAsync(base64BlockId, new MemoryStream(bytesToSend, true), null).ConfigureAwait(false);
blocklist.Add(base64BlockId);
}
while (bytesRemain > 0);
// post blocklist
await blob.PutBlockListAsync(blocklist).ConfigureAwait(false);
}
catch (Exception ex)
{
}
}
답변
1 Blindy Aug 20 2020 at 00:25
첫째, 필요하지 않은 것은 디스크에 쓰지 마십시오. 당신의 목표가 여기에 무엇인지는 완전히 명확하지 않지만, 애초에 당신이 왜 그런 필요를 갖게되었는지는 알 수 없습니다.
즉, 송신 기능을 진공 상태에서 취하면 지금 수행하는 작업은 다음과 같습니다.
메모리에있는 전체 (말한대로) 대용량 파일 읽기
각 청크에 대해 완전히 새로운 배열을 할당하고, 청크를 복사하고, 그 위에을 놓은
MemoryStream
다음 전송합니다.
그것은 스트리밍이 수행되는 방식이 아닙니다.
대신, 아무것도 읽지 않고 파일 스트림을 연 다음 필요한만큼 많은 청크를 반복하고 미리 할당 된 하나의 버퍼에서 각 청크를 개별적으로 읽어야합니다 (새 바이트 배열을 계속 할당하지 마십시오). 정말 필요하고 청크를 보낸 다음 계속 반복하십시오. 당신의 쓰레기 수집가가 감사 할 것입니다.