2014-11-30 3 views
1

У меня есть этот рекурсивный метод copyFolder, который копирует (исходные измененные) файлы/подпапки параллельно.Параллельное или последовательное копирование файлов в WinRT

copyFileIfNewerAsync = function(sourceFile, destFolder) { 
    return destFolder.tryGetItemAsync(sourceFile.name).then(function(destFile) { 
    if (destFile) { 
     return WinJS.Promise.join({ 
     sourceProperties: sourceFile.getBasicPropertiesAsync(), 
     destProperties: destFile.getBasicPropertiesAsync() 
     }).then(function(_arg) { 
     var destProperties, sourceProperties; 
     sourceProperties = _arg.sourceProperties, destProperties = _arg.destProperties; 
     if (sourceProperties.size !== destProperties.size && sourceProperties.dateModified > destProperties.dateModified) { 
      logger.debug("Updating " + destFolder.path + "\\" + destFile.name); 
      return sourceFile.copyAsync(destFolder, sourceFile.name, NameCollisionOption.replaceExisting); 
     } else { 
      return logger.trace("" + destFolder.path + "\\" + destFile.name + " up-to-date (" + destProperties.dateModified + ")"); 
     } 
     }); 
    } else { 
     logger.debug("Copying " + sourceFile.name + " to " + destFolder.path); 
     return sourceFile.copyAsync(destFolder, sourceFile.name, NameCollisionOption.replaceExisting); 
    } 
    }); 
}; 
copyFolderAsync = function(destFolder, sourceFolder) { 
    return destFolder.createFolderAsync(sourceFolder.name, CreationCollisionOption.openIfExists).then(function(destSubFolder) { 
    return sourceFolder.getItemsAsync().then(function(items) { 
     return WinJS.Promise.join(items.map(function(item) { 
     if (item instanceof Windows.Storage.StorageFile) { 
      return copyFileIfNewerAsync(item, destSubFolder); 
     } else { 
      return copyFolderAsync(destSubFolder, item); 
     } 
     })); 
    }); 
    }); 
}; 

Кажется, что это очень усиливает систему. Может быть, последовательный подход к копированию будет менее напряженным для системы и, в конце концов, еще быстрее?

Если да, как бы мне пришлось реорганизовать код, чтобы он запускался последовательно?

обновление

о WinJS.Scheduler

preloadAsync = (serialNumbers, expert) -> 
    assert(expert) 
    assert(serialNumbers) 
    serialNumbers = [serialNumbers] unless Array.isArray(serialNumbers) 
    preloadPromise?.cancel() 
    preloadPromise = serialNumbers.reduce((p, serialNumber) -> 
     p.then(WinJS.Utilities.Scheduler.schedulePromiseBelowNormal) 
     .then() -> 
     preloadOneAsync(serialNumber, expert) 
     .then null, (error) -> 
     if error.name isnt "Canceled" 
      logger.error("Could not create preloaded inspection #{serialNumber}", error) 
    , WinJS.Promise.as()) 

Это должно затем запланировать все загрузки при низкой ПРИО?

ответ

1

Да, я полагаю, что вы перегружаете файловую систему слишком большим количеством параллельных операций, так как каждый асинхронный вызов будет откручивать собственный поток. Я думаю, что разумным подходом к попытке было бы позволить каждой папке работать параллельно, а файлы в каждой папке выполняться последовательно.

Хитрость заключается в том, чтобы последовательно запускать каждую копию файла aync. Для этого существует полезная схема обещаний для последовательной цепочки из массива входных аргументов, которую я описываю на странице 1208 (Приложение A) моей бесплатной книги Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition.

В вашем случае, я думаю, вы захотите сделать отдельный вызов sourceFolder.getFoldersAsync и выполнить итерацию результатов вызова copyFolderAsync. Затем вызовите sourceFolder.getFilesAsync, чтобы получить массив файлов. Это можно использовать с методом array.reduce, как показано в шаблоне, который строит накопленный массив обещаний по одному. Используя код из книги, ваш «op» будет вызовом copyFileIfNewerAsync.

Вот модифицированный фрагмент кода из моего примера, чтобы показать это:

//This op function attached other arguments to each call 
var op = function (file) { return copyFileIfNewerAsync(file); }; 

//The arguments we want to process are in "files" from getFilesAsync 

//This code creates a parameterized promise chain from the items array and the async call 
//in op. By using WinJS.Promise.as for the initializer we can just call p.then inside 
//the callback. 
var endPromise = files.reduce(function (p, file) { 
    return p.then(function (r) { 
     //The first result from WinJS.Promise.as will be undefined, so skip logging 
     if (r !== undefined) { App.log("operation completed with results = " + r) }; 

     return op(file); 
    }); 
}, WinJS.Promise.as()); 

//endPromise is fulfilled with the last operation's results when the whole chain is complete. 
endPromise.done(function (r) { 
    App.log("Final promise complete with results = " + r); 
}); 
+0

Благодаря Kraig. Попробуй и вернись сюда. – philk

+0

Kraig переплетается в течение некоторого времени, чтобы действительно копировать файлы во время простоя UI, я мог бы использовать WinJS.Utilities.Scheduler.schedulePromiseBelowNormal? – philk

+0

Да, я проверил с людьми в Windows и обнаружил, что асинхронные вызовы WinRT, порожденные в обратном вызове с более низким приоритетом, также будут работать с более низким приоритетом. (С технической точки зрения, они наследуют приоритет CoreDispatcher этого обратного вызова JS.) Поэтому использование планировщика для запуска на холостом ходу должно препятствовать возникновению проблем с пользовательским интерфейсом. –