네트워크 리소스에서 디스크로 파일을 다운로드하는 코드를 작성하고 있습니다. 네트워크에서 읽기는 비동기 적으로 수행되며 쓰기도 수행됩니다. 비동기 적 호출이 사실 동 기적으로 호출되는 문제를 관찰하고 있으므로 각 새 반복이 스택에 새로운 함수 호출을 생성합니다. 여기HttpWebRequest 비동기 호출이 스택을 채우고 Windows Phone에서 Reactive Extensions를 제거했습니다.
private IsolatedStorageFileStream fileStream = null;
private HttpWebRequest webRequest = null;
private Stream responseStream = null;
private long responsePosition = 0;
private static int BufferSize = 4096;
private byte[] bufferRead = new byte[BufferSize];
private void button4_Click(object sender, RoutedEventArgs e)
{
string fileName = "TestFile.mp3";
using(var store = IsolatedStorageFile.GetUserStoreForApplication())
{
if(store.FileExists(fileName))
{
store.DeleteFile(fileName);
}
fileStream = store.OpenFile(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read);
webRequest = WebRequest.Create(new Uri(mpsUri.Text)) as HttpWebRequest;
var observableRequest = Observable.FromAsyncPattern<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse);
Observable.Timeout(observableRequest.Invoke(), TimeSpan.FromMinutes(2))
.Subscribe(response => { ResponseCallback(response); }, exception => { TimeoutCallback(); });
}
}
private void TimeoutCallback()
{
webRequest.Abort();
MessageBox.Show("Request timed-out");
}
private void ResponseCallback(WebResponse webResponse)
{
if((webResponse as HttpWebResponse).StatusCode != HttpStatusCode.OK)
{
MessageBox.Show("Download error1");
}
else
{
responseStream = webResponse.GetResponseStream();
if(responsePosition != 0)
{
responseStream.Position = responsePosition;
}
IAsyncResult readResult = responseStream.BeginRead(bufferRead, 0, BufferSize, new AsyncCallback(ReadCallback), null);
return;
}
webResponse.Close();
MessageBox.Show("Download error2");
}
private void ReadCallback(IAsyncResult asyncResult)
{
int bytes = responseStream.EndRead(asyncResult);
DLog.Info("store:{0}, current size:{1}", bytes, fileStream.Length);
if(bytes > 0)
{
fileStream.BeginWrite(bufferRead, 0, bytes, WriteCallback, null);
return;
}
responseStream.Close();
MessageBox.Show("Download error3");
}
private void WriteCallback(IAsyncResult asyncResult)
{
DLog.Info("Stored!");
responseStream.BeginRead(bufferRead, 0, BufferSize, new AsyncCallback(ReadCallback), null);
}
그리고 (약간 수정) 스택의 코드 조각입니다 :
(...)
MainPage.ReadCallback(System.IAsyncResult asyncResult) Line 190 + 0x1b bytes C#
Stream.BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x6c bytes
MainPage.WriteCallback(System.IAsyncResult asyncResult) Line 200 + 0x1f bytes C#
Stream.BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x64 bytes
FileStream.BeginWrite(byte[] array, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x7c bytes
IsolatedStorageFileStream.BeginWrite(byte[] buffer, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x1a bytes
MainPage.ReadCallback(System.IAsyncResult asyncResult) Line 190 + 0x1b bytes C#
Stream.BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x6c bytes
MainPage.WriteCallback(System.IAsyncResult asyncResult) Line 200 + 0x1f bytes C#
Stream.BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x64 bytes
FileStream.BeginWrite(byte[] array, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x7c bytes
IsolatedStorageFileStream.BeginWrite(byte[] buffer, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x1a bytes
MainPage.ReadCallback(System.IAsyncResult asyncResult) Line 190 + 0x1b bytes C#
Stream.BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x6c bytes
MainPage.WriteCallback(System.IAsyncResult asyncResult) Line 200 + 0x1f bytes C#
Stream.BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x64 bytes
FileStream.BeginWrite(byte[] array, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x7c bytes
IsolatedStorageFileStream.BeginWrite(byte[] buffer, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x1a bytes
MainPage.ReadCallback(System.IAsyncResult asyncResult) Line 190 + 0x1b bytes C#
Stream.BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x6c bytes
MainPage.WriteCallback(System.IAsyncResult asyncResult) Line 200 + 0x1f bytes C#
Stream.BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) + 0x64 bytes
FileStream.BeginWrite(byte[] array, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x7c bytes
IsolatedStorageFileStream.BeginWrite(byte[] buffer, int offset, int numBytes, System.AsyncCallback userCallback, object stateObject) + 0x1a bytes
(...)
이 스택은 비동기 콜백 즉시 호출되는 것을 보여주고 실행에 반환하지 않습니다 여기에 코드입니다 모든 반복이 완료 될 때까지 호출 함수. 함수가 다른 함수를 비동기 적으로 호출하면 호출 함수가 완료되고 스택에서 제거 될 때까지 콜백이 호출되지 않을 것으로 예상됩니다. 그러나 현재의 동작으로 인해 스택이 두세 번 반복되어 오버플로가 발생합니다.
반응 확장을 사용하여이 제한 사항을 해결하려고합니다 (또는 정말 버그라고해서는 안됩니까?). 그래서 관측 패턴에 의해 네트워크 스트림을 읽고 반복, 예를 대체하기 위해 노력하고 있어요 :
var readerFunc = Observable.FromAsyncPattern<byte[], int, int, int>(responseStream.BeginRead, responseStream.EndRead);
그러나 여기에 문제의
는 반응 라이브러리의 윈도우 폰 버전은 두 가지를 지원하기 위해 아래로 분리 사실이다 매개 변수 및 반환 매개 변수 : 내가 위에서 원하는대로 그 세 개의 매개 변수를 필요로하기 때문에Observable.FromAsyncPattern<T1, T2, TResult>
그래서 내가 읽기 기능을 정의 할 수 없습니다. 라이브러리의 다운로드 가능한 버전조차도 더 많은 매개 변수를 제공하지 않습니다.
마지막으로, 내 질문은 :
비동기 호출이 동 기적으로 호출되는 원래 문제를 해결 작업 스택을 채우는 다른 방법으로는 반응성 확장을 사용하는 것보다 다른 있나요?
그렇지 않으면 Windows Phone에서 사용할 수있는 Reactive Extensions의 제한된 버전을 사용하여 네트워크 스트림에서 읽고 스트림을 비동기 적으로 쓸 수 있습니까?
대단히 감사합니다!
원래 문제가 해결되었습니다. 감사. BTW는 비동기 적으로 완료되도록 완료하는 API가 있습니까? – Amiramix
BTW2, 코드가 동기식으로 완료되면 두 스트림을 동시에 읽고 쓰는 것과는 차이가 있습니까? ResponseCallback 함수는 분리 된 스레드에서 이미 호출되어야하므로 동기식으로 UI에 아무런 차이가 없어야합니다. – Amiramix
매번 동기화가된다면 sync API를 사용하지 않으시겠습니까? – spender