7

Descrizione del problema: si scrive una libreria che contiene alcuni algoritmi/attività che possono richiedere molto tempo per terminare, per vari motivi: computazionale, file system, comunicazione di rete ecc Si vuole essere in grado di:.NET: meccanismo per la sincronizzazione di attività di lunga durata

  1. inviare alcune informazioni di avanzamento sul compito (progresso, attività di registrazione etc.)
  2. hanno un modo per annullare l'operazione prima del completamento se qualche segnale esterno o proprietà è stata impostato.

Ho implementato un framework per questo, ma ciò richiede che tutte queste attività debbano fare riferimento a un assembly che contiene questo framework.

La mia domanda: esiste un meccanismo già integrato in .NET framework (3.5 o inferiore) per il problema descritto sopra?

So che potrei usare gli eventi, ma questo significherebbe che le attività di lunga durata dovrebbero esporre tali eventi, che penso sia un sovraccarico. Idealmente, voglio avere un framework che nasconda i problemi di multithreading ed è dipendente dall'iniezione di dipendenze, ma non dipenderà da un assembly addizionale personalizzato e non inquinerebbe l'interfaccia originale.

Spero di aver descritto il problema abbastanza bene. In caso contrario, posso pubblicare alcuni esempi di interfacce dal mio framework.

UPDATE: OK, penso che la mia descrizione del problema abbia bisogno di un po 'di chiarimenti :). Quando dico "long-running", non intendo "long" nel senso del flusso di lavoro. Sto lavorando a un'app di mapping WinForms che fa ogni genere di cose, come la generazione di relief contours. Per fare ciò, deve prima scaricare i file di dati di elevazione da un server FTP, decomprimerli e quindi eseguire alcuni calcoli. Ho scritto il codice per questo molto tempo fa, ma al fine di renderlo più GUI-friendly, devo vari controlli retrofit - per esempio, rilevando che l'utente ha cliccato sul tasto Esci e interrompere il processo.

Fondamentalmente la mia preoccupazione è: come scrivere un codice che può essere utilizzato in un secondo momento (se mai) in un ambiente GUI, in cui non è possibile eseguire semplicemente tutto nel thread GUI principale e bloccare l'intera applicazione. La sfida è trovare un modo per rendere il codice adatto agli scopi della GUI senza legarlo a una particolare piattaforma della GUI.

+0

Primi pensieri_ Si può esaminare utilizzando System.Diagnostics.PerformanceCounter per eseguire la registrazione delle attività numeriche. Quindi qualsiasi applicazione che ne conosce il nome può leggere i dati. Per segnalare un annullamento, puoi utilizzare EventWaitHandle con un handle denominato. Entrambi questi approcci non richiedono il collegamento delle DLL, ma richiedono una denominazione "stringa" condivisa. Oppure vai al percorso WWF come suggerisce @mark. –

+0

Voglio evitare che il codice della libreria "pulito e innocente" si mescoli con il gruppo difficile come attesa handle, thread e WMI;) Sto cercando un'astrazione di questi pattern (preferibilmente attraverso le interfacce C#, per renderlo più testabile). –

risposta

6

Sembra molto simile a Windows Workflow Foundation.

+0

WWF è un po 'eccessivo per il problema che sto descrivendo (ho aggiornato la descrizione). –

2

Dai un'occhiata al modello della saga. Non è integrato nel framework ma può essere implementato. In alternativa, sia NServiceBus che MassTransit hanno implementazioni di questo. Arnon RGO ha una bozza del suo libro (sarà sempre finita) che lo descrive here.

Nella mia esperienza sempre andare con NServiceBus è molto più semplice di WF, ed è anche più potente (anche se non ho guardato WF 4, che per tutte le descrizioni è un vicino rielaborazione completa di WF come Microsoft hanno riconosciuto le carenze di questo).

Anche se non si desidera un framework come NServiceBus o MassTransit, vale la pena considerare il pattern stesso, poiché si adatta molto strettamente allo spazio del problema da ciò che è stato descritto.

1

Dipende da come complicato il sistema è. Per problemi relativamente semplici, potresti probabilmente usare lo BackgroundWorker class da .NET 2.0.Supporta la segnalazione dell'avanzamento dell'operazione utilizzando l'evento OnProgressChanged e supporta anche l'annullamento dell'attività in background utilizzando il metodo CancelAsync.

La classe è controllato dagli eventi, ma dal momento che è già una parte della classe, non credo sia alcun sovraccarico per voi:

var bw = new BackgroundWorker(); 
bw.DoWork += new DoWorkEventHandler(DoWork); 
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RunWorkerCompleted); 
bw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged); 
  • Il metodo DoWork viene eseguito per l'esecuzione l'attività in background (può segnalare l'avanzamento chiamando lo bw.ReportProgress e verificare la cancellazione in sospeso utilizzando bw.CancellationPending).

  • Il metodo RunWorkerCompleted viene eseguito sul thread GUI quando l'operazione viene completata (che vi dà un bel modo per sincronizzare senza preoccuparsi di concorrenza)

  • L'evento ProgressChanged viene attivato ogni volta che il metodo di DoWork riporta qualche cambiamento progresso .

Per problemi più semplici, credo che potresti rappresentare i tuoi compiti come addetti ai lavori.

+0

@Tomas, utilizzo già BackgroundWorker per questi scopi, ma indirettamente a livello di infrastruttura. Il problema è che la rappresentazione delle attività direttamente come classe BackgroundWorker implica che sarà _always_ eseguito in modalità asincrona, il che non è necessariamente il caso. –

+0

Sì. Mi aspettavo che BackgroundWorker non fosse abbastanza potente nel tuo caso. Spero che possa aiutare qualcuno a cercare come superare questo tipo di problema in un ambiente più semplice in futuro. –

0

Preferisco utilizzare i metodi di callback per segnalare il thread dell'interfaccia utente quando qualcosa è stato fatto o il progresso deve essere aggiornato. È possibile passare oggetti complessi e la richiamata può restituire un valore nel caso in cui sia necessario segnalare il thread di lavoro. E ti è permesso avere più callback definiti a seconda di quanto chatty hai bisogno dei tuoi lavoratori.

Problemi correlati