创建异步任务队列 - 使用 BlockingCollection C#

Create a queue of async tasks - using BlockingCollection C#

我有一个 WPF C# 应用程序,它使用 API 向 Facebook 和 Twitter 发送消息。为此,我有一个主要的静态 class,我可以在其中发送字符串消息和一些参数。当用户只是间歇性地发出通知时,代码工作正常。但是当用户一次发出多个通知时,它就不起作用了。我想要的是:

我研究过使用 BlockingCollection,但不太了解如何使其工作。

这是我当前的代码,我希望它尽可能接近于此:

class PublishAnnouncement {
 //This function is callled upon in many parts of the program and acts as a general publisher
 public static void PostAnnoucment(string message, string TwAccountKey, string FbAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow) {
  //First it is published to facebook
  BackgroundWorker FacebookWorker = new BackgroundWorker();
  FacebookWorker.DoWork += (obj, e) => FacebookDoWork(message, FbAccountKey);
  FacebookWorker.RunWorkerAsync();

  //Then it is published to twitter - This is where it appears to fail
  BackgroundWorker TwitterWorker = new BackgroundWorker();
  TwitterWorker.DoWork += (obj, e) => TwitterDoWork(message, TwAccountKey, JourneyRefID, latness, mainWindow, 0);
  TwitterWorker.RunWorkerAsync();
 }

 private static void FacebookDoWork(string message, string FbAccountKey) {
  //STAGE 1 - Facebook
  //First the program will attempt to post a Facebook post.
  try {
   //If it is to be posted by one of the additional Facebook Pages and 
   //not by the default page.

   var client = new RestClient("https://graph.facebook.com/v3.0/");

   var request = new RestRequest("{pageId}/feed", Method.POST);
   request.AddParameter("message", message); // adds to POST or URL querystring based on Method
   request.AddParameter("access_token", Properties.Settings.Default.FBPageAccessToken);
   request.AddUrlSegment("pageId", Properties.Settings.Default.FBPageID); // replaces matching token in request.Resource
   IRestResponse response = client.Execute(request);

   if (response.IsSuccessful == false) {
    Console.WriteLine(response.Content);
    Console.WriteLine("");
   }

  } catch (Exception ex) {
   Console.WriteLine(ex.ToString());
  }
 }

 private static void TwitterDoWork(string message, string TwAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow, int Attempts) {
  //STAGE 2 - Twitter
  //Once a Facebook post has/has not been posted the program will attempt to send a tweet.
  try {

   Auth.SetUserCredentials(Properties.Settings.Default.TwConsumerKey, Properties.Settings.Default.TwConsumerSecret, Properties.Settings.Default.TwUserAccessToken, Properties.Settings.Default.TwUserAccessSecret);
   var tweet = Tweet.PublishTweet(message);
   foreach(var ID in JourneyRefID)
        AddTweetID(tweet.Id, ID, latness, mainWindow);


  } catch (Exception ex) {
   foreach(var ID in JourneyRefID)
        AddTweetID(0, ID, latness, mainWindow);

   Console.WriteLine(ex.Message);
  }
 }
}

我建议在 PostAnnouncement 中使用 Mutex。 请在此处查看已接受的答案 - 使用锁示例: Usage of Mutex in c#

class PublishAnnouncement {
private static readonly object syncLock = new object();

public static void PostAnnoucment(string message, string TwAccountKey, string FbAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow) {
    lock(syncLock) {
        //First it is published to facebook
        BackgroundWorker FacebookWorker = new BackgroundWorker();
        FacebookWorker.DoWork += (obj, e) => FacebookDoWork(message, FbAccountKey);
        FacebookWorker.RunWorkerAsync();

        //Then it is published to twitter - This is where it appears to fail
        BackgroundWorker TwitterWorker = new BackgroundWorker();
        TwitterWorker.DoWork += (obj, e) => TwitterDoWork(message, TwAccountKey, JourneyRefID, latness, mainWindow, 0);
        TwitterWorker.RunWorkerAsync();

        //etc
    }
}

}

锁一次只允许一个线程通过,将所有线程堆叠起来。请注意,我已将锁设为静态。 (无论有多少 class 的实例在任何时候被使用,所有调用线程都只会创建和引用一个锁对象)。

如果您想将锁移到后台线程中:

class   PublishAnnouncement {
private static  readonly    object  syncLockForTwitter  =   new object();
private static  readonly    object  syncLockForFacebook =   new object();
//This  function    is  callled upon    in  many    parts   of  the program and acts    as  a   general publisher
public  static  void    PostAnnoucment(string   message,    string  TwAccountKey,   string  FbAccountKey,   string[]    JourneyRefID,   double  latness,    MainWindow  mainWindow) {
    //First it  is  published   to  facebook
    BackgroundWorker    FacebookWorker  =   new BackgroundWorker();
    FacebookWorker.DoWork   +=  (obj,   e)  =>  FacebookDoWork(message, FbAccountKey);
    FacebookWorker.RunWorkerAsync();

    //Then  it  is  published   to  twitter -   This    is  where   it  appears to  fail
    BackgroundWorker    TwitterWorker   =   new BackgroundWorker();
    TwitterWorker.DoWork    +=  (obj,   e)  =>  TwitterDoWork(message,  TwAccountKey,   JourneyRefID,   latness,    mainWindow, 0);
    TwitterWorker.RunWorkerAsync();
}

private static  void    FacebookDoWork(string   message,    string  FbAccountKey)   {
    lock(syncLockForFacebook)   {
    //STAGE 1   -   Facebook
    //First the program will    attempt to  post    a   Facebook    post.
        try {
            //If    it  is  to  be  posted  by  one of  the additional  Facebook    Pages   and 
            //not   by  the default page.

            var client  =   new RestClient("https://graph.facebook.com/v3.0/");

            var request =   new RestRequest("{pageId}/feed",    Method.POST);
            request.AddParameter("message", message);   //  adds    to  POST    or  URL querystring based   on  Method
            request.AddParameter("access_token",    Properties.Settings.Default.FBPageAccessToken);
            request.AddUrlSegment("pageId", Properties.Settings.Default.FBPageID);  //  replaces    matching    token   in  request.Resource
            IRestResponse   response    =   client.Execute(request);

            if  (response.IsSuccessful  ==  false)  {
                Console.WriteLine(response.Content);
                Console.WriteLine("");
            }

        }   catch   (Exception  ex) {
            Console.WriteLine(ex.ToString());
        }
    }
}

private static  void    TwitterDoWork(string    message,    string  TwAccountKey,   string[]    JourneyRefID,   double  latness,    MainWindow  mainWindow, int Attempts)   {
    lock(syncLockForTwitter)    {
    //STAGE 2   -   Twitter
    //Once  a   Facebook    post    has/has not been    posted  the program will    attempt to  send    a   tweet.
        try {

            Auth.SetUserCredentials(Properties.Settings.Default.TwConsumerKey,  Properties.Settings.Default.TwConsumerSecret,   Properties.Settings.Default.TwUserAccessToken,  Properties.Settings.Default.TwUserAccessSecret);
            var tweet   =   Tweet.PublishTweet(message);
            foreach(var ID  in  JourneyRefID)
                                AddTweetID(tweet.Id,    ID, latness,    mainWindow);


        }   catch   (Exception  ex) {
            foreach(var ID  in  JourneyRefID)
                                AddTweetID(0,   ID, latness,    mainWindow);

            Console.WriteLine(ex.Message);
        }
    }
}

}