Создать очередь асинхронных задач - используя BlockingCollection C # - PullRequest
0 голосов
/ 02 сентября 2018

У меня есть приложение WPF C #, которое отправляет сообщение в Facebook и Twitter с помощью API. Для этого у меня есть один основной статический класс, куда я могу отправить строковое сообщение и несколько параметров. Код работает нормально, когда пользователь только периодически отправляет объявления. Но когда пользователь отправляет несколько объявлений одновременно, это не работает. То, что я хочу, это:

  • Делать по объявлению по одному в заказе FIFO
  • Не нарушать графический интерфейс
  • Разрешить запросы в очереди.
  • Разрешать запросы в любом месте программы и в любое время

Я изучал использование 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);
  }
 }
}

1 Ответ

0 голосов
/ 02 сентября 2018

Я бы предложил использовать Mutex в PostAnnouncement. Смотрите принятый ответ здесь - используйте пример блокировки: Использование Mutex в 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   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);
        }
    }
}

}

...