1

Azure からいくつかのオブジェクトをロードする必要があります。時間を短縮するために、それらを5つずつロードすることを計画しました(一種の遅延ロード):

ProductManager.LoadProduct call my ProductAccess.LoadProduct この最後のメソッドは、Azure から製品をロードし、マネージャーが製品を取得できるようにイベントを発生させます。その後、製品を受け取ると、ProductAccess.LoadProduct を再度呼び出します。など....

クロス プラットフォーム コードであるため、await/async を使用できません (monodroid/monotouch の安定版にはまだ await/async がありません)。

最初のロードは正しく、2 番目の呼び出しは機能しますが、タスクが実行されていないようです (2 番目のタスクを開始しないでください...)。スレッド番号を確認すると、2回目はメインスレッドで Task.Factory.StartNew(() => が実行されており、長時間実行を指定して修正しようとしていますが、それでもうまくいきません。

これが私のコードです:

マネージャー側:

public void LoadProduct() 
{
    ProductAccess.LoadProductsAsync()
}

public void receiveProductsAsync(Object pa, EventArgs e)
{
    if (((ProductEventArgs)e).GetAttribute.Equals("LoadProductsAsync"))
    {
        IoC.Resolve<IProductAccess>().RequestEnded -= receiveProductsAsync;

        if ( ((ProductEventArgs)e).LP).Count() != 0)                       
           LoadProductsAsync();

        Products = Products.Concat(((ProductEventArgs)e).LP).ToList();
        if (((ProductEventArgs)e).E != null)
        {
            if (RequestEnded != null)
                RequestEnded(this, new OperationEventArgs() { Result = false, E = ((ProductEventArgs)e).E, GetAttribute = "LoadProductsAsync" });
        }
        else
        {
            if (RequestEnded != null)
            {
                RequestEnded(this, new OperationEventArgs() { Result = true, GetAttribute = "LoadProductsAsync" });
            }
        }
    }
}

アクセス側:

public void LoadProductsAsync()
{
    Task<ProductEventArgs>.Factory.StartNew(() =>
    {
        var longRunningTask = new Task<ProductEventArgs>(() =>
        {
            try
            {
                var _items = this.table.Select(x => new Product(.....)).Skip(nbrProductLoaded).Take(nbrProductToLoadAtEachTime).ToListAsync().Result;
                this.nbrProductLoaded += _items.Count();
                Task.Factory.StartNew(() => synchronizeFavorite(_items));
                return new ProductEventArgs() { LP = _items, GetAttribute = "LoadProductsAsync" };
            }
            catch (Exception e)
            {
                return new ProductEventArgs() { E = e, GetAttribute = "LoadProductsAsync" };
            }
        }, TaskCreationOptions.LongRunning);

        longRunningTask.Start();

        if (longRunningTask.Wait(timeout)) 
            return longRunningTask.Result;

        return new ProductEventArgs() { E = new Exception("timed out"), GetAttribute = "LoadProductsAsync" };

    }, TaskCreationOptions.LongRunning).ContinueWith((x) => {
        handleResult(x.Result);
    }, TaskScheduler.FromCurrentSynchronizationContext());
}
4

1 に答える 1

1

Task.Factory.StartNewはデフォルトで現在の を使用しますTaskScheduler

最初はタスク内で実行していないため、currentTaskSchedulerがデフォルトですTaskScheduler(スレッド プールで実行されます)。

handleResultを使用して元のコンテキストにスケジュールを戻すと、メイン スレッドのタスク内で実行されますTaskScheduler.FromCurrentSynchronizationContexthandleResultしたがって、そのコンテキストでは、 currentTaskSchedulerは UITaskSchedulerであり、 default ではありませんTaskScheduler

これを修正するには、スレッド プール スレッドで実行するTaskScheduler.Defaultanyに明示的に渡します (および remove )。StartNewLongRunning

于 2013-05-31T11:36:08.193 に答える