Я ничего с этим видом асинхронные чтение/запись петли?


Вот мой код:

public static void CopyStream(Stream input, Stream output)
{
    var size = 8192;

    var inBuffer = new byte[size];
    var outBuffer = new byte[size];

    IAsyncResult writeAsync = null;

    int count;
    while (true)
    {
        var readAsync = input.BeginRead(inBuffer, 0, size, null, null);

        if (writeAsync != null)
        {
            output.EndWrite(writeAsync);
            writeAsync = null;
        }

        count = input.EndRead(readAsync);
        inBuffer.CopyTo(outBuffer, 0);

        if (count > 0)
        {
            writeAsync = output.BeginWrite(outBuffer, 0, count, null, null);
        }
        else
        {
            break;
        }
    }
}

Это действительно мой первый кусок кода с помощью begin и End асинхронная модель. Мне просто интересно, если у меня есть какие-то явные проблемы.

Или, есть какие-то улучшения, которые вы можете видеть, чтобы сделать это еще лучше?



1875
10
задан 21 февраля 2011 в 01:02 Источник Поделиться
Комментарии
2 ответа

Это не совсем понятно, каковы ваши цели с этот кусок кода. Три возможности, которые приходят на ум:


  • CopyStream должны быть асинхронными. Как написано, оно не соответствует этой цели, так как он блокирует по результатам метод endread и EndWrite. Если это ваша цель, вы должны использовать методы обратного вызова и не вызывать конечные методы, пока ваши обратные вызовы были названы. Вы также должны изменить подпись CopyStream вернуться iasyncresult и принимать функцию обратного вызова и государства в качестве параметров.

  • CopyStream стоит скрывать подробности базовых асинхронных вызовов от пользователей, но и сама синхронно. Ваш код выполняет эту цель, но есть несколько вещей, которые можно использовать очистки.

  • CopyStream стоит скрывать подробности базовых асинхронных вызовов, а также повысить производительность, убедившись, что писатель занят все время и не сидеть в ожидании читает, насколько это возможно. Похоже, это может быть вашей целью из-за попытки чтения/записи параллельно, но только один выдающийся читать и писать, вы действительно не получаете много из него. Для того, чтобы правильно реализовать это, вам нужно использовать какой-нить ридер и какой-нить писатель, в очередь записываются. Читатель читает так же быстро, как он может и вставляет куски данных в очередь, которой автор потом пишет так же быстро, как он может или как быстро, как они появляются.

Редактировать:

В качестве примера, как написать этот код, используя очереди, см. ниже. Обратите внимание, что мне не нужно, чтобы раскрутить какой-нить, потому что я могу просто использовать метод endread/обратные вызовы EndWrite и исходный поток ждать сигнала, чтобы быть поднят. Кроме того, это слегка протестировали первый проект, так что будьте осторожны, что там могут быть ошибки, скрывающиеся там. Этот тип кода является сложным и трудно получить права, и должно использоваться только, когда действительно необходимо для действительной производительности причин. Если сложность не оправдана, я бы просто использовать синхронные методы read и write для упрощения кода, насколько это возможно.

public static void CopyStream(Stream input, Stream output)
{
AutoResetEvent completed = new AutoResetEvent(false);
BeginRead(new CopyStreamState(completed, input, output));

completed.WaitOne();
}

private static void BeginRead(CopyStreamState state)
{
const int bufferSize = 8192;

state.InputBuffer = new byte[bufferSize];
state.Input.BeginRead(state.InputBuffer, 0, bufferSize, ReadCallback, state);
}

private static void ReadCallback(IAsyncResult ar)
{
CopyStreamState state = (CopyStreamState)ar.AsyncState;

int bytesRead = state.Input.EndRead(ar);
if (bytesRead > 0)
{
byte[] dataToWrite = state.InputBuffer;

if (bytesRead < state.InputBuffer.Length)
{
dataToWrite = new byte[bytesRead];
Array.Copy(state.InputBuffer, dataToWrite, bytesRead);
}

EnqueueWriteData(state, dataToWrite);
BeginRead(state);
}
else
{
state.FinishedReading = true;
}

BeginWriteOrComplete(state);
}

private static void EnqueueWriteData(CopyStreamState state, byte[] data)
{
lock (state)
{
state.WriteQueue.Enqueue(data);
}
}

private static void BeginWriteOrComplete(CopyStreamState state)
{
lock (state)
{
if (!state.WriteInProgress)
{
if (state.WriteQueue.Count > 0)
{
byte[] outputBuffer = state.WriteQueue.Dequeue();
state.WriteInProgress = true;
state.Output.BeginWrite(outputBuffer, 0, outputBuffer.Length, WriteCallback, state);
}
else if (state.FinishedReading)
{
state.Completed.Set();
}
}
}
}

private static void WriteCallback(IAsyncResult ar)
{
CopyStreamState state = (CopyStreamState)ar.AsyncState;
state.Output.EndWrite(ar);

lock (state)
{
state.WriteInProgress = false;
BeginWriteOrComplete(state);
}
}

private class CopyStreamState
{
public CopyStreamState(
AutoResetEvent completed,
Stream input,
Stream output)
{
this.Completed = completed;
this.Input = input;
this.Output = output;
this.WriteQueue = new Queue<byte[]>();
}

public AutoResetEvent Completed { get; private set; }
public Stream Input { get; private set; }
public Stream Output { get; private set; }
public Queue<byte[]> WriteQueue { get; private set; }

public byte[] InputBuffer { get; set; }
public bool FinishedReading { get; set; }
public bool WriteInProgress { get; set; }
}

7
ответ дан 21 февраля 2011 в 03:02 Источник Поделиться

Только быстрое Примечание: Если я выполняю свой код правильно, я просто не могу увидеть, как последний если (writeAsync != нуль) может не быть правдой.

1
ответ дан 21 февраля 2011 в 10:02 Источник Поделиться