C# LinqToTwitter-如何在考虑并发性的情况下正确处理可观察流

C# LinqToTwitter-如何在考虑并发性的情况下正确处理可观察流,c#,concurrency,dispose,linq-to-twitter,rx.net,C#,Concurrency,Dispose,Linq To Twitter,Rx.net,我用LinqToTwitter创建了一个可观察的集合IObservable,如下所示。问题是,当我处理第一个可观察对象并订阅一个新的可观察对象时,这个实现存在并发性问题 我怎样才能正确地处理第一个可观察到的数据 (下面的示例应该是完整的,可以正常工作,只需添加引用包和Twitter凭据即可。) 以下是出现此问题的示例: using System; using System.Reactive.Linq; namespace Twitter.Cli { class Program

我用LinqToTwitter创建了一个可观察的集合
IObservable
,如下所示。问题是,当我处理第一个可观察对象并订阅一个新的可观察对象时,这个实现存在并发性问题

我怎样才能正确地处理第一个可观察到的数据

(下面的示例应该是完整的,可以正常工作,只需添加引用包和Twitter凭据即可。)

以下是出现此问题的示例:

using System;
using System.Reactive.Linq;

namespace Twitter.Cli
{
    class Program
    {
        public static void Main(string[] args)
        {
            var twitter = new TwitterApi.Twitter();

            var search1 = twitter.AllTweetsAbout("windows")
                .Sample(TimeSpan.FromSeconds(1));

            var search2 = twitter.AllTweetsAbout("android")
                .Sample(TimeSpan.FromSeconds(1));

            var sub = search1.Subscribe(
                x =>
                    Console.WriteLine("TOPIC = {0} - CONTAINS STRING: {1}", x.Topic, x.Text.ToLower().Contains(x.Topic.ToLower()) ? "YES" : "NO"));

            Console.ReadLine();

            sub.Dispose();

            /* 
            * If you stop the processing here for a while so that the StartAsync method can be executed 
            * within the closure everything works fine because disposed is set to true 
            * before the second observable is created 
            */
            //Console.ReadLine(); 

            search2.Subscribe(
                x =>
                    Console.WriteLine("TOPIC = {0} - CONTAINS STRING: {1}", x.Topic, x.Text.ToLower().Contains(x.Topic.ToLower()) ? "YES" : "NO"));

            Console.ReadLine();
        }
    }
}
如果在创建第二个可观察对象之前执行第一个可观察对象创建结束时的
StartAsync
方法,则
disposed
将设置为
true
,一切正常

但是如果在下一次执行
StartAsync
disposed
中的第一个闭包之前创建了第二个可观察对象,则再次将
s.CloseStream()设置为false从未被调用

以下是可观察对象的创建:

using System;
using System.Configuration;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using LinqToTwitter;

namespace TwitterApi
{
    public class Twitter
    {
        private readonly SingleUserAuthorizer _auth = new SingleUserAuthorizer
        {
            CredentialStore = new InMemoryCredentialStore
            {
                ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
                ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"],
                OAuthToken = ConfigurationManager.AppSettings["authtoken"],
                OAuthTokenSecret = ConfigurationManager.AppSettings["authtokensecret"],
            }
        };

        private readonly TwitterContext _twitterCtx;

        public Twitter()
        {
            if (String.IsNullOrWhiteSpace(_auth.CredentialStore.ConsumerKey)
                || String.IsNullOrWhiteSpace(_auth.CredentialStore.ConsumerSecret)
                || String.IsNullOrWhiteSpace(_auth.CredentialStore.OAuthToken)
                || String.IsNullOrWhiteSpace(_auth.CredentialStore.OAuthTokenSecret))
                throw new Exception("User Credentials are not set. Please update your App.config file.");

            _twitterCtx = new TwitterContext(_auth);
        }

        public IObservable<Tweet> AllTweetsAbout(string topic)
        {
            return Observable.Create<Tweet>(o =>
            {
                var query = from s in _twitterCtx.Streaming
                            where s.Type == StreamingType.Filter &&
                                    s.Track == topic
                            select s;

                var disposed = false;

                query.StartAsync(async s =>
                {
                    if (disposed)
                        s.CloseStream();
                    else
                    {
                        Tweet t;
                        if (Tweet.TryParse(s.Content, topic, out t))
                        {
                            o.OnNext(t);
                        }
                    }
                });

                return Disposable.Create(() => disposed = true);
            });
        }
    }
}
using System;
using Newtonsoft.Json.Linq;

namespace TwitterApi
{
    public class Tweet
    {
        public string User { get; private set; }
        public string Text { get; private set; }
        public string Topic { get; private set; }

        public static bool TryParse(string json, string topic, out Tweet tweet)
        {
            try
            {
                dynamic parsed = JObject.Parse(json);
                tweet = new Tweet
                {
                    User = parsed.user.screen_name,
                    Text = parsed.text,
                    Topic = topic,
                };
                return true;
            }
            catch (Exception)
            {
                tweet = null;
                return false;
            }
        }

        private Tweet()
        {

        }
    }
}