.net 如何使用反应式框架将两个异步操作链接在一起?
我真正想做的就是完成两个异步操作,一个接一个。例如.net 如何使用反应式框架将两个异步操作链接在一起?,.net,asynchronous,system.reactive,.net,Asynchronous,System.reactive,我真正想做的就是完成两个异步操作,一个接一个。例如 下载网站X。完成后,下载网站Y。从两个观察对象中进行SelectMany(使用ToAsync将操作作为IObservables获取),就像LINQ SelectMany(或使用语法糖)一样: 还有其他选择,但这取决于您的具体情况。我自己不喜欢这样的建议,但是 如果您需要按顺序执行两个操作,请按顺序执行(您仍然可以在与main不同的线程上执行) 如果您仍然希望在代码中分离任务,那么新构造与System.Parallel是合适的: var task
下载网站X。完成后,下载网站Y。从两个观察对象中进行SelectMany(使用ToAsync将操作作为IObservables获取),就像LINQ SelectMany(或使用语法糖)一样:
还有其他选择,但这取决于您的具体情况。我自己不喜欢这样的建议,但是 如果您需要按顺序执行两个操作,请按顺序执行(您仍然可以在与main不同的线程上执行) 如果您仍然希望在代码中分离任务,那么新构造与System.Parallel是合适的:
var task1 = Task.Factory.StartNew (() => FirstTask());
var task2 = task1.ContinueWith (frst => SecondTask ());
如果这是一种破坏系统反应性的方法,那么试试Observable.GenerateInSequence——但这肯定是过火了。记住,observable是enumerable的对应项,最好以类似的方式使用(对数据进行迭代)。它不是运行异步操作的工具 编辑:我想承认我错了,理查德是对的——在我回复时,我对RX不太满意。现在我认为RX是启动异步操作最自然的方式。然而,理查德的回答有点肤浅,应该是:
var result =
from x in XDownload.ToAsync()()
from y in YDownload.ToAsync()()
select y
也许是以下几点:
static IObservable<DownloadProgressChangedEventArgs> CreateDownloadFileObservable(string url, string fileName)
{
IObservable<DownloadProgressChangedEventArgs> observable =
Observable.CreateWithDisposable<DownloadProgressChangedEventArgs>(o =>
{
var cancellationTokenSource = new CancellationTokenSource();
Scheduler.TaskPool.Schedule
(
() =>
{
Thread.Sleep(3000);
if (!cancellationTokenSource.Token.IsCancellationRequested)
{
WebClient client = new WebClient();
client.DownloadFileAsync(new Uri(url), fileName,fileName);
DownloadProgressChangedEventHandler prgChangedHandler = null;
prgChangedHandler = (s,e) =>
{
o.OnNext(e);
};
AsyncCompletedEventHandler handler = null;
handler = (s, e) =>
{
prgChangedHandler -= prgChangedHandler;
if (e.Error != null)
{
o.OnError(e.Error);
}
client.DownloadFileCompleted -= handler;
o.OnCompleted();
};
client.DownloadFileCompleted += handler;
client.DownloadProgressChanged += prgChangedHandler;
}
else
{
Console.WriteLine("Cancelling download of {0}",fileName);
}
}
);
return cancellationTokenSource;
}
);
return observable;
}
static void Main(string[] args)
{
var obs1 = CreateDownloadFileObservable("http://www.cnn.com", "cnn.htm");
var obs2 = CreateDownloadFileObservable("http://www.bing.com", "bing.htm");
var result = obs1.Concat(obs2);
var subscription = result.Subscribe(a => Console.WriteLine("{0} -- {1}% complete ",a.UserState,a.ProgressPercentage), e=> Console.WriteLine(e.Message),()=> Console.WriteLine("Completed"));
Console.ReadKey();
subscription.Dispose();
Console.WriteLine("Press a key to exit");
Console.ReadKey();
}
“它不是一个运行异步操作的工具。”我完全不同意这种说法,延续monad(Rx)正是我们合成异步操作所需要的,因为我们显式地传递任何状态,并且所有的副作用都得到了管理。首先创建Rx的主要原因之一是异步和并行编程。从可观察管道创建异步操作-是。使用Observable启动异步任务(特别是一个或两个)而不观察结果-这将过于复杂。是的,Rx的全部要点是异步操作的可组合性。我刚刚完成了一个严重依赖Rx的应用程序的编写,我使用的代码与Richards的示例一模一样。在一个地方,我需要提交多达18个web服务请求来加载数据,如果没有Rx,我需要的代码将是Rx的10倍。如果“X”或“Y”多次返回,我们将开始看到交叉连接行为。它非常适合只返回一次的异步操作。但是为了安全起见,使用Prune扩展方法将只允许一个通知通过,因此对于类似webservice调用的东西是一个好主意。
static IObservable<DownloadProgressChangedEventArgs> CreateDownloadFileObservable(string url, string fileName)
{
IObservable<DownloadProgressChangedEventArgs> observable =
Observable.CreateWithDisposable<DownloadProgressChangedEventArgs>(o =>
{
var cancellationTokenSource = new CancellationTokenSource();
Scheduler.TaskPool.Schedule
(
() =>
{
Thread.Sleep(3000);
if (!cancellationTokenSource.Token.IsCancellationRequested)
{
WebClient client = new WebClient();
client.DownloadFileAsync(new Uri(url), fileName,fileName);
DownloadProgressChangedEventHandler prgChangedHandler = null;
prgChangedHandler = (s,e) =>
{
o.OnNext(e);
};
AsyncCompletedEventHandler handler = null;
handler = (s, e) =>
{
prgChangedHandler -= prgChangedHandler;
if (e.Error != null)
{
o.OnError(e.Error);
}
client.DownloadFileCompleted -= handler;
o.OnCompleted();
};
client.DownloadFileCompleted += handler;
client.DownloadProgressChanged += prgChangedHandler;
}
else
{
Console.WriteLine("Cancelling download of {0}",fileName);
}
}
);
return cancellationTokenSource;
}
);
return observable;
}
static void Main(string[] args)
{
var obs1 = CreateDownloadFileObservable("http://www.cnn.com", "cnn.htm");
var obs2 = CreateDownloadFileObservable("http://www.bing.com", "bing.htm");
var result = obs1.Concat(obs2);
var subscription = result.Subscribe(a => Console.WriteLine("{0} -- {1}% complete ",a.UserState,a.ProgressPercentage), e=> Console.WriteLine(e.Message),()=> Console.WriteLine("Completed"));
Console.ReadKey();
subscription.Dispose();
Console.WriteLine("Press a key to exit");
Console.ReadKey();
}
WebClient c = new WebClient();
c.CreateDownloadFileObservable ("www.bing.com","bing.htm");