Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Windows 8线程改进-Task.Run()的替代方案?_C#_Multithreading - Fatal编程技术网

C# Windows 8线程改进-Task.Run()的替代方案?

C# Windows 8线程改进-Task.Run()的替代方案?,c#,multithreading,C#,Multithreading,我继承了一个C#/XAML/win8应用程序。有些代码设置为每n秒运行一次 设置的代码是: if(!_syncThreadStarted) { await Task.Run(() => SyncToDatabase()); _syncThreadStarted = true; } 上面的代码只运行一次 然后在SyncToDatabase()中,我们有: 方法反序列化和更新查询内存中的对象集合,并将这些对象推送到web服务 有时,向web服务发送请求的时间比预期的要长,这意

我继承了一个C#/XAML/win8应用程序。有些代码设置为每n秒运行一次

设置的代码是:

if(!_syncThreadStarted)
{
    await Task.Run(() => SyncToDatabase());
    _syncThreadStarted = true;
}
上面的代码只运行一次

然后在SyncToDatabase()中,我们有:

方法反序列化和更新查询内存中的对象集合,并将这些对象推送到web服务

有时,向web服务发送请求的时间比预期的要长,这意味着发送重复的项目

问题:有没有一种方法可以让线程或某种类型的线程池/后台工作线程在SyncToDatabase()方法中停止/中止/销毁,然后在完成后初始化/启动它?这将确保在前一个请求仍处于挂起状态时不会触发后续请求

编辑:我对线程不是很了解,但我想要的逻辑是:

创建每x秒运行一次方法的线程,当它启动该线程时,停止“每x秒运行一次”部分,在线程完成后再次启动“每x秒运行一次”部分

例如,如果线程在上午10:01:30开始,直到上午10:01:39(9秒)才完成,则下一个线程应在上午10:01:44(工作完成后5秒)开始-这有意义吗?我不希望同时运行两个或多个线程

以下是我的上述代码:

var period = TimeSpan.FromSeconds(5);
var completed = true;
ThreadPoolTimer syncTimer = ThreadPoolTimer.CreatePeriodicTimer(async (source) =>
{
    // stop further threads from starting (in case this work takes longer than var period)
    syncTimer.Cancel();
    DatabaseSyncer dbSyncer = new DatabaseSyncer();
    await dbSyncer.DeserializeAndUpdate(); // makes webservices calls

    Dispatcher.RunAsync(CoreDispatcerPriority.High, async () =>
    {
        // Update UI
    }

    completed = true;
}, period,
(source) =>
{
    if(!completed)
    {
        syncTimer.Cancel(); // not sure if this is correct...
    }
}
谢谢,
Andrew)

我可能误解了这个问题,但是执行
SynchToDatabase()
将等待
wait dbSyncer.DeserializeAndUpdaet()
(由于
wait
关键字,请参见图;)的完成,然后再执行延续,这将延迟10毫秒(您想要10毫秒还是10秒?
任务的参数。延迟
以毫秒为单位),然后返回以重新执行
DbSyncer
方法,因此我看不出问题。

这不是Windows 8特有的。通常
任务。Run
用于CPU限制的工作,将其卸载到池线程并保留UI(或核心服务循环)响应。在您的情况下,据我所知,主要负载是
dbSyncer.DeserializeAndUpdate
,它已经是异步的,很可能是网络IO绑定的,而不是CPU绑定的

此外,原始代码的作者在等待任务后执行
\u syncThreadStarted=true
。运行(()=>SyncToDatabase())。这没有意义,因为池线程上的工作在执行
\u syncThreadStarted=true
时就已经完成了,这多亏了
wait

要取消
SyncToDatabase
中的循环,可以使用。
SyncToDatabase
本身是
async
方法吗?我想是这样,因为
while循环中有一个
wait
。鉴于此,调用它的代码可能如下所示:

if(_syncTask != null && !_syncTask.IsCompleted)
{
    _ct.Cancel();
    // here you may want to make sure that the pending task has been fully shut down, 
    // keeping possible re-entrancy in mind
    // See: https://stackoverflow.com/questions/18999827/a-pattern-for-self-cancelling-and-restarting-task
    _syncTask = null;
}
_ct = new CancellationTokenSource();
// _syncTask = SyncToDatabase(ct.Token); // do not await
// edited to run on another thread, as requested by the OP
var _syncTask = Task.Run(async () => await SyncToDatabase(ct.Token), ct.Token);
_syncThreadStarted = true;
SyncToDatabase
可能看起来像:

async Task SyncToDatabase(CancellationToken token)
{
    while (true)
    {
        token.ThrowIfCancellationRequested();
        DatabaseSyncer dbSyncer = new DatabaseSyncer();
        await dbSyncer.DeserializeAndUpdate();
        await Task.Delay(10, token); // after elapsed time re-run above code
    }
}

查看有关如何取消和重新启动任务的详细信息。

谢谢您的回答。因此,您回答的第一部分是注册任务?它似乎不会阻止任务在SyncToDatabase运行时发生,除非我误解了。@andrewb、
\u syncTask
\u ct
是类的字段。您可以检查使用
\u syncTask=SyncToDatabase(ct.Token)启动新任务之前请停止
并首先取消任务的旧实例。因此,只有一个任务实例处于活动状态。您的代码是否创建了单独的线程?如果可能,我需要SyncToDatabase在单独的非UI线程中运行。@andrewb,您确定需要另一个线程吗?请参阅我关于CPU和IO绑定任务的说明。无论如何,我已经更新了代码以运行它n另一个线程。确保您了解嵌套任务的工作原理:我需要UI线程保持响应。请参阅我更新的原始帖子,以更清楚地解释我需要什么。
async Task SyncToDatabase(CancellationToken token)
{
    while (true)
    {
        token.ThrowIfCancellationRequested();
        DatabaseSyncer dbSyncer = new DatabaseSyncer();
        await dbSyncer.DeserializeAndUpdate();
        await Task.Delay(10, token); // after elapsed time re-run above code
    }
}