在考慮了解決方案并分析了所有答案后,我洗掉了我的帖子
uj5u.com熱心網友回復:
a 的重點BackgroundWorker是將東西從 UI 執行緒中推出。你這樣做了,但隨后Bw_DoWork你立即將東西推回UI 執行緒,使用this.Dispatcher.Invoke,它會阻塞作業執行緒,直到現在在 UI 執行緒上運行的作業完成。
基本上:洗掉該this.Dispatcher.Invoke呼叫,然后在 worker 上運行代碼。如果您需要觸摸 UI,那么您需要在 UI 執行緒上處理這些位,但僅限于那些按鈕。
同樣,我懷疑mutliocr應該使用 dispatch invoke,它當然不應該將 UI 執行緒更改為后臺執行緒 ( Thread.CurrentThread.IsBackground = true;)。
uj5u.com熱心網友回復:
您的代碼非常非常臭和丑陋。您似乎完全沒有遵循任何命名約定。本地和班級成員是駝峰式和 PascalCase,有些根本不使用大小寫,有些則使用下劃線。你真的應該仔細檢查你的代碼,考慮很多方面并清理它。也有一些冗余。
你的一個非常糟糕的習慣是過度使用Dispatcher. 例如,您創建一個后臺執行緒并發布完整的!此執行緒的作業回傳到Dispatcher/UI 執行緒。資源的巨大浪費并消除了任何多執行緒優勢。
您不想將所有作業都放在Dispatcher. 您想將 CPU 密集型 eork 卸載到后臺執行緒。您希望盡可能使用異步 API。因為你想讓 UI 保持回應。Dispatcher表示 UI 執行緒。
一些非常重要的興趣點
GrantAccess實施是對用戶權利的嚴重安全侵犯。不要修改訪問規則。而是過濾并忽略當前用戶無權訪問的資源。特別重要的是,您永遠不要將訪問權限恢復到原始狀態。- 作為一般規則:不要在后臺執行緒上執行 IO 相關代碼(例如,資料庫、HTTP 流、檔案 IO)。請改用異步 API。僅將執行緒用于 CPU 密集型作業(例如計算、轉換)。
File有一個你應該經常使用的異步 API。例如File.OpenRead回傳一個FileStream暴露FileStream.ReadAsnyc成員的。如果您在處理檔案時需要更多便利,例如逐行讀取,則將其包裝FileStream成StreamReader/StreamWriter并使用類似的成員StreamReader.ReadLineAsync- 為避免
Dispatcher呼叫,請將所需的 UI 值作為引數傳遞給并發方法。更好地使用資料系結(這不會消除跨執行緒寫入問題,但會使您的代碼更具可讀性并消除Dispatcher讀取值的呼叫)。看看下面的重構File_process方法。它展示了如何將 UI 值作為引數傳遞給converttiffpdfreducer然后在后臺執行緒上執行的方法。 - 考慮為長期運行添加取消支持
converttiffpdfreducer() - 避免呼叫
ToArray或ToList上IEnumerable。這些方法是立即執行最初延遲的 LINQ 查詢的終結器。 - 不要打電話
ToArray或ToList對結果之類的EnumerateFiles。這些方法用于提高性能,因為它們逐項回傳檔案系統物件。如果您遞回迭代整個檔案系統結構,這一點尤其重要。如果檔案系統樹很深很寬,呼叫ToArray將強制迭代完成,然后立即回傳所有結果。ToArrayonEnumerateFiles就像使用GetFiles. 您應該檢查完整的代碼并正確重構它。你總是用Enumerate XYZ 錯!
》 EnumerateFiles 和 GetFiles 方法的區別如下: 使用 EnumerateFiles 時,可以在回傳整個集合之前開始列舉名稱集合。使用 GetFiles 時,必須等待整個名稱陣列回傳后才能進行訪問陣列。因此,當您處理許多檔案和目錄時,EnumerateFiles 可以更高效。”
- 使用資料系結而不是直接訪問 UI 元素。這允許您在不使用
Dispatcher. - 永遠不要從建構式執行長時間運行的操作
- 永遠不要從建構式呼叫異步代碼
- 始終保持物件實體化便宜且快速,并且沒有隱藏的性能/資源成本
- 永遠抓不到
Exception。始終捕獲專門的例外型別。 - 不要使用空的 catch 塊。如果可以,要么處理例外,要么讓它使您的應用程式崩潰,讓您有機會修復錯誤。當您吞下例外時,錯誤將悄悄地潛入您的應用程式。你將很難發現它們。記錄例外不被視為處理 - 在這種情況下重新拋出。
- 如果使用
using陳述句宣告資源,則不必顯式關閉資源。Dispose一旦指令指標離開using作用域,隱式呼叫將自動關閉資源。
實施所有建議將顯著加快您的應用程式。
I have refactored only some of your code to show how to properly use async APIs and Task.Run instead of the BackgroundWorker. I have removed every Dispatcher invocation. Instead of direct access to UI elements in order to read their values from the background thread, I have extracted those values before invoking the concurent method and passed those prefetched values as method arguments. If you would use data binding you could read the property values directly and therefore ommit the method parameters.
The MainWindow should be shown manually from App.xaml.cs to allow asynchronous and longrunning initialization of the instance. For this pattern let the class that requires such initialization implement a public InitializeAsync method that can be awaited from the caller's context. Alternatively use Lazy<T> to defer initialization when required e.g., when initialization is depending on explicit access to members.
Although the refactored code will significantly improve the applicatoin's performance, you will have do to do some important refactoring yourself (following the pattern of the already refactored code sections).
Take a look at
InitializeAsyncandWriteLnAsyncto learn how to use the async file IO API.converttiffpdfreducerto learn how to use theEnumerateFilesandEnumerateDirectoriesmethods properly in order to significantly improve the performance.mutliocr,mergeandconverttiffpdfreducerto learn how pass UI element values as argument in order to avoidDispatcherinvocations.start_btn_Clickandconverttiffpdfreducerto learn how to implemnent cancellation and to guard your API against calls during an uninitialized state
App.xaml
<Application Startup="Application_Startup">
</Application>
App.xaml.cs
class App : Application
{
private async void Application_Startup(object sender, StartupEventArgs e)
{
var mainWindow = new MainWindow();
// Because InitializeAsync depends on UI elements,
// we have to wait until the Ui is loaded.
mainWindow.Loaded = OnMainWindowLoaded;
// Either call Show() before initialization or after.
// If before, ensure access to uninitialized members and resources is denied
// e.g. by querying the MainWindow.IsInitialized property in public members and event handlers.
mainWindow.Show();
}
private async void OnMainWindowLoaded(object sender, EventArgs args)
=> await mainWindow.InitializeAsync();
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public bool IsInitialized { get; private set; }
private bool IsBusy { get; set; }
private CancellationTokenSource CancellationTokenSource { get; set; }
public MainWindow()
{
InitializeComponent();
CancellationTokenSource = new CancellationTokenSource();
}
// Execute blocking initialization routines asynchronously
public async Task InitializeAsync()
{
if (IsInitialized)
{
return;
}
// Will execute the intesive CPU bound work on a background thread.
await File_process(Cancellationtoken.None);
string configpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"path.txt");
// Use async API to read/write from/to files and other IO resources
using (FileStream configfile = File.OpenRead(configpath))
{
using (var fileReader = new StreamReader(configfile))
{
var configFileContent = new List<string>();
while (!fileReader.EndOfStream)
{
string lineOfFile = await fileReader.ReadLineAsync();
configFileContent.Add(lineOfFile);
}
if (configFileContent.Any())
{
ip.Text = configFileContent[0];
GrantAccess(configFileContent[0]);
op.Text = configFileContent[1];
GrantAccess(configFileContent[1]);
ex_tb.Text = configFileContent[2];
GrantAccess(configFileContent[2]);
Protb.Text = configFileContent[3];
GrantAccess(configFileContent[3]);
}
}
}
cbPDFConform.Items.Clear();
for (int i = 0; i < Enum.GetNames(typeof(PdfConformance)).Length - 1; i )
{
ComboBoxItem cbi = new ComboBoxItem();
cbi.Content = Enum.GetName(typeof(PdfConformance), (PdfConformance)i);
PdfConformance test = (PdfConformance)i;
cbi.Tag = (PdfConformance)i;
cbPDFConform.Items.Add(cbi);
}
cbPDFConform.SelectedIndex = 0;
cbProcessorCount.Items.Clear();
for (int i = 1; i <= Environment.ProcessorCount; i )
{
cbProcessorCount.Items.Add(i.ToString());
if (Environment.ProcessorCount / 2 == i) { cbProcessorCount.SelectedIndex = i - 1; }
}
LicenseManager oLicenseManager = new LicenseManager();
oLicenseManager.RegisterKEY("");
threadSyn = SynchronizationContext.Current;
IsInitialiezd = true;
}
public async Task File_process(CancellationToken cancellationToken)
{
// Read UI values to avoid Dispatcher calls from the background thread
string ipText = ip.Text;
string protbText = Protb.Text;
string opText = op.Text;
// Execute the intesive CPU bound work on a background thread.
await Task.Run(() => converttiffpdfreducer(ipText, protbText, opText, cancellationToken), cancellationToken);
}
private async Task DoWorkAsync(CancellationToken cancellationToken)
{
IsBusy = true;
using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"path.txt"), false))
{
await sw.WriteLineAsync(ip.Text);
await sw.WriteLineAsync(op.Text);
await sw.WriteLineAsync(ex_tb.Text);
await sw.WriteLineAsync(Protb.Text);
}
try
{
cancellationToken.ThrowIfCancellationRequested();
var watch1 = new System.Diagnostics.Stopwatch();
watch1.Start();
// Consider to add cancellation support to File_process
await File_process(cancellationToken);
watch1.Stop();
TimeSpan ts1 = watch1.Elapsed;
ts1.ToString("mm\\:ss");
if (MergeChk.IsChecked == false)
{
value = "OCRed";
}
await WriteLnAsync("All documents have been successfully " value " " ts1 " " DateTime.Now " " Environment.UserName, cancellationToken);
IsBusy = false;
}
catch (OperationCanceledException)
{
IsBusy = false;
throw;
}
}
private async Task WriteLnAsync(string text, CancellationToken cancellationToken)
{
logtb.Text = text Environment.NewLine;
log_list.Add(text);
log_cap = text Environment.NewLine log_cap;
using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"FileProcessing_log.txt"), false))
{
foreach (string l in log_list)
{
cancellationToken.ThrowIfCancellationRequested();
await sw.WriteLineAsync(l);
}
}
}
private async void start_btn_Click(object sender, RoutedEventArgs e)
{
if (!IsInitialized)
{
return;
}
if (IsBusy)
{
// Cancel the longrunning operation.
this.CancellationTokenSource.Cancel();
}
start_btn.Content = "Start";
try
{
await DoWorkAsync(CancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
CancellationTokenSource?.Dispose();
CancellationTokenSource = new CancellationTokenSource();
}
}
private void converttiffpdfreducer(
string ipText,
string protbText,
string opText,
CancellationToken cancellationToken)
{
string[] dir = null;
string box = string.Empty;
string box1 = string.Empty;
string[] gg = null;
PdfConformance optPDFConform = PdfConformance.Unknown;
foreach (var directoryPath in Directory.EnumerateDirectories(ipText, "*.*", SearchOption.AllDirectories).Where(l => l.Length != 0))
{
cancellationToken.ThrowIfCancellationRequested();
foreach (var filePath in Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.AllDirectories))
{
cancellationToken.ThrowIfCancellationRequested();
string getext = Path.GetExtension(filePath);
string fd = Path.GetDirectoryName(filePath);
string op_path = fd.Replace(ipText, protbText);
string getextension = Path.GetExtension(filePath);
string dict = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Redist", "OCR");
string outputPath = fd.Replace(ipText, protbText);
string FNAME = Path.GetFileNameWithoutExtension(filePath);
string fn = Path.GetDirectoryName(filePath).Replace(ipText, protbText);
string filen = Path.Combine(outputPath, fn, FNAME ".pdf");
string savefile = Path.Combine(op_path, filen);
box = Path.GetDirectoryName(filePath);
box1 = Path.GetDirectoryName(box);
using (GdPictureDocumentConverter oConverter = new GdPictureDocumentConverter())
{
GdPictureStatus status = new GdPictureStatus();
if (Path.GetExtension(filePath).ToUpper() == ".PDF")
{
status = oConverter.LoadFromFile(filePath, GdPicture14.DocumentFormat.DocumentFormatPDF);
}
else if (Path.GetExtension(filePath).ToUpper() == ".TIF" || Path.GetExtension(filePath).ToUpper() == ".TIFF")
{
status = oConverter.LoadFromFile(filePath, GdPicture14.DocumentFormat.DocumentFormatTIFF);
}
else if (Path.GetExtension(filePath).ToUpper() == ".JPG")
{
status = oConverter.LoadFromFile(filePath, GdPicture14.DocumentFormat.DocumentFormatJPEG);
}
if (status == GdPictureStatus.OK)
{
if (!Directory.Exists(op_path))
{
Directory.CreateDirectory(op_path);
}
GrantAccess(op_path);
optPDFConform = (PdfConformance)((ComboBoxItem)cbPDFConform.SelectedItem).Tag;
status = oConverter.SaveAsPDF(savefile, optPDFConform);
if (status == GdPictureStatus.OK)
{ }
else
{ }
}
else
{ }
}
}
}
string BOXX = box.Replace(ipText, protbText);
// TODO::Refactor 'merge' and replace 'ToArray' with 'foreach'
string[] Arr = Directory.EnumerateFiles(BOXX, "*.pdf", SearchOption.AllDirectories).ToArray();
if (MergeChk.IsChecked == true)
{ merge(Arr, protbText); }
else if (MergeChk.IsChecked == false)
{
mutliocr(Arr);
}
}
private string[] merge(string[] arr, string protbText, string opText)
{
string box = string.Empty;
string box1 = string.Empty; string[] gg = null;
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
box = Path.GetDirectoryName(arr[0]);
box1 = Path.GetDirectoryName(box);
string dirName = Directory.GetParent(arr[0]).FullName;
string BOXFILES = Path.GetDirectoryName(dirName);
string folder = Directory.GetParent(arr[0]).FullName.Replace(protbText, opText);
string ocrfolder = (new FileInfo(arr[0]).Directory.FullName).Replace(protbText, opText);
string fn = Directory.GetParent(arr[0]).Name;
string filen = Path.Combine(ocrfolder, folder, fn ".pdf");
if (!Directory.Exists(ocrfolder))
{
Directory.CreateDirectory(ocrfolder);
}
GrantAccess(ocrfolder);
using (GdPicturePDF oGdPicturePDF = new GdPicturePDF())
{
GdPictureStatus status = oGdPicturePDF.MergeDocuments(ref arr, filen);
if (status == GdPictureStatus.OK)
{ }
else
{ }
oGdPicturePDF.Dispose();
}
Directory.Delete(box, true);
string BOXX = box.Replace(protbText, opText);//op
string[] files = Directory.EnumerateFiles(BOXX, "*.pdf", SearchOption.AllDirectories).ToArray();
if (MergeChk.IsChecked == true)
{ mutliocr(files, protbText, opText); }
}));
return gg;
}
private string[] mutliocr(string[] arr, string protbText, string opText)
{
string box = string.Empty;
string box1 = string.Empty;
try
{
string filepath = string.Empty;
if (MergeChk.IsChecked == true)
{ filepath = opText; }
else if (MergeChk.IsChecked == false)
{ filepath = protbText; }
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
Thread.CurrentThread.IsBackground = true;
var watch2 = new System.Diagnostics.Stopwatch();
watch2.Start();
string[] getfilearray = arr;
for (int f = 0; f < getfilearray.Length; f )
{
string dirName = Directory.GetParent(getfilearray[f]).FullName;
string folder = Directory.GetParent(getfilearray[f]).FullName;
box = Path.GetDirectoryName(getfilearray[f]);
box1 = Path.GetDirectoryName(box);
string getextension = Path.GetExtension(getfilearray[f]);
string[] newF = Directory.EnumerateFiles(dirName, "*.*", SearchOption.AllDirectories).ToArray();
string FN = Directory.GetParent(getfilearray[f]).Name;
string ocrfolder = (new FileInfo(getfilearray[f]).Directory.FullName);
string filen = Path.Combine(ocrfolder, folder, FN "-ocr" getextension);
string dict = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Redist", "OCR");
if (!Directory.Exists(ocrfolder))
{
Directory.CreateDirectory(ocrfolder);
}
GrantAccess(ocrfolder);
GdPicturePDF oGdPicturePDF = new GdPicturePDF();
oGdPicturePDF.OcrPagesDone = OcrPagesDone;
void OcrPagesDone(GdPictureStatus status1)
{
if (oGdPicturePDF.SaveToFile(filen) == GdPictureStatus.OK)
{ }
else
MessageBox.Show("PDF: The OCR-ed file has failed to save. Status: " oGdPicturePDF.GetStat().ToString());
}
GdPictureStatus status = GdPictureStatus.OK;
if (oGdPicturePDF.LoadFromFile(getfilearray[f], false) == GdPictureStatus.OK)
if (status == GdPictureStatus.OK)
{
if (oGdPicturePDF.OcrPages_4("*", 0, "eng", dict, "", 300, OCRMode.FavorSpeed, 1, true) == GdPictureStatus.OK)
if (status == GdPictureStatus.OK)
{ }
else
{ MessageBox.Show("PDF: The OCR process has failed. Status: " status.ToString()); }
}
else
{ MessageBox.Show("PDF: The PDF file has failed to load. Status: " status.ToString()); }
oGdPicturePDF.Dispose();
GrantAccess(getfilearray[f]);
File.Delete(getfilearray[f]);
watch2.Stop();
TimeSpan ts2 = watch2.Elapsed;
ts2.ToString("mm\\:ss");
WriteLn(" OCR pages " filen.Replace(opText, "") " " ts2 " " DateTime.Now);
}
if (MergeChk.IsChecked == true)
{
foreach (string str in Directory.EnumerateFiles(opText, "*.pdf", SearchOption.AllDirectories).ToArray())
{
if (Path.GetFileNameWithoutExtension(str).EndsWith("-ocr"))
File.Move(str, Path.Combine(Path.GetDirectoryName(str), Path.GetFileNameWithoutExtension(str).Substring(0, Path.GetFileNameWithoutExtension(str).Length - 4) ".pdf"));
}
}
if (MergeChk.IsChecked == false)
{
FileSystem.MoveDirectory(protbText, opText, UIOption.AllDialogs);
Directory.CreateDirectory(protbText);
string FF = string.Empty;
foreach (string str in Directory.EnumerateFiles(opText, "*.pdf", SearchOption.AllDirectories))
{
if (Path.GetFileNameWithoutExtension(str).EndsWith("-ocr"))
File.Move(str, Path.Combine(Path.GetDirectoryName(str), Path.GetFileNameWithoutExtension(str).Substring(0, Path.GetFileNameWithoutExtension(str).Length - 4) ".pdf"));
}
}
}));
}
catch (Exception mul)
{
}
return arr;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/314844.html
