Domanda

Sto scrivendo qualcosa che carica i record da SQL Server su una coda Azure. La cosa è che il numero di elementi nel risultato select potrebbe essere molto grande, quindi vorrei iniziare le cose di accodamento mentre i dati vengono ancora recuperati.

Sto cercando di sfruttare EF6 (ASYNC), tutti i metodi ASYNC e e TPL per l'enquequeing parallelo. Quindi ho:

        // This defines queue that Generator will publsh to and 
        // QueueManager wil read from. More info:
        // http://msdn.microsoft.com/en-us/library/hh228601(v=vs.110).aspx
        var queue = new BufferBlock<ProcessQueueItem>();

        // Configure queue listener first
        var result = this.ReceiveAndEnqueue(queue);

        // Start generation process
        var tasks = generator.Generate(batchId);
.

Il ricevitore è semplice:

    private async Task ReceiveAndEnqueue(ISourceBlock<ProcessQueueItem> queue)
    {
        while (await queue.OutputAvailableAsync())
        {
            var processQueueItem = await queue.ReceiveAsync();
            await this.queueManager.Enqueue(processQueueItem);
            this.tasksEnqueued++;
        }
    }
.

Il generatore Generare () La firma è la seguente:

public void Generate(Guid someId, ITargetBlock<ProcessQueueItem> target)
.

che chiama il metodo SENDASYNC () sull'obiettivo per posizionare nuovi elementi. Quello che sto facendo in questo momento sta dividendo il numero totale di risultati in "lotti", caricandoli dentro e inviandoli Async, fino a quando tutto è fatto:

    public void Generate(Guid batchId, ITargetBlock<ProcessQueueItem> target)
    {
        var accountPromise = this.AccountStatusRepository.GetAccountsByBatchId(batchId.ToString());
        accountPromise.Wait();
        var accounts = accountPromise.Result;

        // Batch configuration
        var itemCount = accounts.Count();
        var numBatches = (int)Math.Ceiling((double)itemCount / this.batchSize);
        Debug.WriteLine("Found {0} items what will be put in {1} batches of {2}", itemCount, numBatches, this.batchSize); 


        for (int i = 0; i < numBatches; i++)
        {
            var itemsToTake = Math.Min(this.batchSize, itemCount - currentIndex);
            Debug.WriteLine("Running batch - skip {0} and take {1}", currentIndex, itemsToTake);

            // Take a subset of the items and place them onto the queue
            var batch = accounts.Skip(currentIndex).Take(itemsToTake);

            // Generate a list of tasks to enqueue the items
            var taskList = new List<Task>(itemsToTake);
            taskList.AddRange(batch.Select(account => target.SendAsync(account.AsProcessQueueItem(batchId))));

            // Return the control when all tasks have been enqueued
            Task.WaitAll(taskList.ToArray());

            currentIndex = currentIndex + this.batchSize;
        } 
.

Questo funziona tuttavia, il mio collega ha osservato - "Non riesco a rendere l'interfaccia più semplice e lasciare generare () e rendere l'interfaccia come:

public Task<IEnumerable<ProcessQueueItem> Generate(Guid someId)
.

A Lot Cleaner e nessuna dipendenza dal metodo generato sulla libreria TPL. Sono totalmente d'accordo, sono solo che se lo faccio, dovrò chiamare

var result = Generate().Wait().Result;
.

ad un certo punto, prima di enqueuminig tutti gli articoli. Questo mi farà aspettare fino a quando tutte le cose vengono caricate ed è in memoria.

Allora, qual è la mia domanda, è: come posso iniziare a utilizzare EF Query Risultati non appena "Groppy in" da un select? Come se EF eseguirà un "rendimento" sui risultati se prendi la mia deriva.

Modifica Penso di aver fatto un errore di pensiero. EF carica gli elementi pigri per impostazione predefinita. Quindi posso solo restituire tutti i risultati come iqueryable <> ma ciò non significa che siano effettivamente caricati dal DB. Allora io iperererò su di loro e ne enquequei.

Modifica 2 No, che non funziona, dal momento che ho bisogno di trasformare l'oggetto dal database nel metodo Genera () ...

È stato utile?

Soluzione

OK, questo è ciò che ho finito con:

    public IEnumerable<ProcessQueueItem> Generate(Guid batchId)
    {
        var accounts = this.AccountStatusRepository.GetAccountsByBatchId(batchId.ToString());

        foreach (var accountStatuse in accounts)
        {
            yield return accountStatuse.AsProcessQueueItem(batchId);
        }
    }
.

Il repository restituisce un Ienumerable di solo alcuni DataContext.Stuff.Vhere (...).Il generatore utilizza il metodo di estensione per trasformare l'entità nel modello di dominio (ProcessQueueTeem) che mediante il mezzo di rendimento viene immediatamente inviato al chiamante del metodo, che inizierà a chiamare il QueueueManager per avviare la coda.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top