如何正确使用Task.Factory.StartNew和.ContinueWith

时间:2019-06-12 14:19:27

标签: c# xamarin xamarin.forms xamarin.android

我有一个Task Factory,可以启动使用REST的Task。

 Task.Factory.StartNew(async () => await App.TodoManager.FirstTimeSyncUser(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t1) => await App.TodoManager.FirstTimeSyncSystemSerial(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t2) => await App.TodoManager.FirstTimeSyncContacts(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t3) => await App.TodoManager.FirstTimeSyncRetailerOutlet(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t4) => await App.TodoManager.FirstTimeSyncCAF(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t5) => await App.TodoManager.FirstTimeSyncCAFActivity(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t6) => await App.TodoManager.FirstTimeSyncEmailRecipient(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t7) => await App.TodoManager.FirstTimeSyncProvince(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t8) => await App.TodoManager.FirstTimeSyncTown(host, database, ipaddress, contact, SyncStatus))
 .ContinueWith(async (t9) => await App.TodoManager.SyncUserLogsClientUpdate(host, database, ipaddress, contact, SyncStatus));

我遇到4个问题:
1.并非所有Task都在执行,这意味着它仅执行从FirstTimeSyncUser到FirstTimeSyncTown的功能。最后一个任务将不会执行。
2.有时,“任务重叠”的执行意味着正在执行2个或更多任务,而不是一次执行一个。
3.当出现异常错误时,不会显示来自每个Task的错误消息,这意味着当出现错误或异常时,每个Task都有一个try-catch系统,它应该显示一个Message框或DisplayAlert来通知使用错误是。 (示例如下)
4.我总是收到一个SQLite.SQLiteException:忙或SQLite.SQLiteException:数据库被锁定。

以下是示例:

public async Task FirstTimeSyncTown(string host, string database, string domain, string contact, Action<string>SyncStatus)
    {
        if (CrossConnectivity.Current.IsConnected)
        {
            var db = DependencyService.Get<ISQLiteDB>();
            var conn = db.GetConnection();

            string apifile = "first-time-sync-town-api.php";
            int count = 0;

            var uri = new Uri(string.Format("http://" + domain + "/TBSApi/" + apifile + "?Host=" + host + "&Database=" + database, string.Empty));

            try
            {
                var response = await client.GetAsync(uri);

                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();

                    if (!string.IsNullOrEmpty(content))
                    {
                        var dataresult = JsonConvert.DeserializeObject<List<TownData>>(content, settings);
                        var datacount = dataresult.Count;

                        for (int i = 0; i < datacount; i++)
                        {
                            SyncStatus("Syncing town " + (count + 1) + " out of " + datacount);

                            var item = dataresult[i];
                            var townID = item.TownID;
                            var provinceID = item.ProvinceID;
                            var town = item.Town;
                            var lastsync = DateTime.Parse(current_datetime);
                            var lastupdated = item.LastUpdated;
                            var deleted = item.Deleted;

                            var insertdata = new TownTable
                            {
                                TownID = townID,
                                ProvinceID = provinceID,
                                Town = town,
                                LastSync = lastsync,
                                LastUpdated = lastupdated,
                                Deleted = deleted
                            };

                            await conn.InsertOrReplaceAsync(insertdata);

                            count++;
                        }

                        //synccount += "Total synced town: " + (count + 1) + "\n";

                        var logType = "App Log";
                        var log = "Initialized first-time sync (<b>Town</b>)  <br/>" + "App Version: <b>" + Constants.appversion + "</b><br/> Device ID: <b>" + Constants.deviceID + "</b>";
                        int logdeleted = 0;

                        await Save_Logs(contact, logType, log, database, logdeleted);

                        Preferences.Set("townchangelastcheck", current_datetime, "private_prefs");
                    }
                }
                else
                {
                    var retry = await App.Current.MainPage.DisplayAlert("First-time Town Sync Error", "Syncing failed. Status Code:\n\n" + response.StatusCode, "Yes", "No");

                    if (retry.Equals(true))
                    {
                        await FirstTimeSyncTown(host, database, domain, contact, SyncStatus);
                    }
                    else
                    {
                        First_Time_OnSyncFailed();
                    }
                }
            }
            catch (Exception ex)
            {
                Crashes.TrackError(ex);
                var retry = await App.Current.MainPage.DisplayAlert("First-time Town Sync Error", "Syncing failed.\n\n Error:\n\n" + ex.Message, "Yes", "No");

                if (retry.Equals(true))
                {
                    await FirstTimeSyncTown(host, database, domain, contact, SyncStatus);
                }
                else
                {
                    First_Time_OnSyncFailed();
                }
            }
        }
        else
        {
            var retry = await App.Current.MainPage.DisplayAlert("First-time Town Sync Error", "Syncing failed. Please connect to the internet to sync your data. Do you want to retry?", "Yes", "No");

            if (retry.Equals(true))
            {
                await FirstTimeSyncTown(host, database, domain, contact, SyncStatus);
            }
            else
            {
                First_Time_OnSyncFailed();
            }
        }
    }

我使用Task.Factory的目的是对Task执行进行排序。有没有更好的方法一个接一个地执行任务,这意味着除非当前任务完成执行,否则其他任务将无法执行?

2 个答案:

答案 0 :(得分:0)

如果您的所有方法都是异步的,并且您想要做的就是让它们按顺序运行,那么为什么需要使用Task.Factory?您能不能像这样顺序等候他们?

await App.TodoManager.FirstTimeSyncUser(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncSystemSerial(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncContacts(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncRetailerOutlet(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncCAF(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncCAFActivity(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncEmailRecipient(host, database, ipaddress, contact, SyncStatus));
await App.TodoManager.FirstTimeSyncProvince(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncTown(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.SyncUserLogsClientUpdate(host, database, ipaddress, contact, SyncStatus);

答案 1 :(得分:0)

Task.Factory.StartNewContinueWith都是非常低级的方法,通常应避免使用。特别是,他们不了解async的代表;这就是为什么您看到执行重叠的原因。

  

我使用Task.Factory的目的是对Task执行进行排序。有没有更好的方法一个接一个地执行任务,这意味着除非当前任务完成执行,否则其他任务将无法执行?

是的。您应该使用asyncawait

await App.TodoManager.FirstTimeSyncUser(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncSystemSerial(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncContacts(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncRetailerOutlet(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncCAF(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncCAFActivity(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncEmailRecipient(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncProvince(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.FirstTimeSyncTown(host, database, ipaddress, contact, SyncStatus);
await App.TodoManager.SyncUserLogsClientUpdate(host, database, ipaddress, contact, SyncStatus);