Comment faire pour forcer la Tâche.Usine.StartNew à un thread d'arrière-plan?
J'ai vu de nombreuses autres questions semblables à cela, mais n'a pas trouvé ma réponse.
Mon problème était que j'étais la création de threads avec le flux suivant:
private void btn_Click(object sender, EventArgs e)
{
service.GetCount(
(count, ex) =>
{
if (ex != null)
return;
for (int i = 0; i < count; i++)
{
service.Get(onItemReceived, i);
}
}
);
}
public void GetCount(Action<int, Exception> callback)
{
var callingThread = TaskScheduler.FromCurrentSynchronizationContext();
Func<int> action = () =>
{
return client.GetCount(); //Synchronous method, could take a long time
};
Action<Task<int>> completeAction = (task) =>
{
Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;
if (callback != null)
callback(task.Result, ex);
};
Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread);
}
public void Get(Action<object, Exception> callback, int index)
{
var callingThread = TaskScheduler.FromCurrentSynchronizationContext();
Func<object> action = () =>
{
return client.Get(index); //Synchronous method, could take a long time
};
Action<Task<object>> completeAction = (task) =>
{
Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;
if (callback != null)
callback(task.Result, ex);
};
Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread);
}
De cette façon, chacun de mes service asynchrone de méthodes de rappel du fil ils ont été à l'origine appelé généralement le thread d'INTERFACE utilisateur). Je suis donc à simuler comment les attendent/async mots-clés travail (je ne peut pas utiliser .NET 4.5).
Le problème avec ce modèle est que je inexplicablement verrouillé sur le thread de l'INTERFACE utilisateur après le premier appel à "ContinueWith". Dans ce cas, si je tente de me frayer 5 threads à chaque processus une fonction synchrone Obtenir, ils exécutent 1 par 1 au lieu d'en parallèle et ils vont bloquer le thread d'INTERFACE utilisateur en faisant de la sorte, même si j'ai essayer de préciser TaskCreationOptions.LongRunning.
Cela n'arrive jamais avec mon premier appel à la Tâche.Usine.StartNew, cela n'arrive que pour les appels suivants de l'intérieur le premier rappel.
OriginalL'auteur Trevor Elliott | 2013-04-11
Vous devez vous connecter pour publier un commentaire.
Afin de forcer le lancement d'un nouveau fil de discussion, vous devez spécifier TaskScheduler.Par défaut dans l'appel à la Tâche.Usine.StartNew comme suit:
Dans mon test, vous n'avez pas besoin de spécifier TaskCreationOptions.LongRunning afin de forcer un thread d'arrière-plan, mais il ne devrait pas faire de mal.
LongRunning
les forces de la création d'un tout nouveau non-thread du pool.il n'a pas la force de rien, c'est un indice pour le planificateur.
En théorie, oui, c'est correct. Dans la pratique, dans l'implémentation actuelle, il en résulte un nouveau thread en cours de création. Alors que je suis d'accord, il pourrait être préférable de supposer qu'il est possible que ce ne sera pas, vous devez supposer que le marquage d'une tâche, tant en cours d'exécution lorsque c'est vraiment ne va consommer des ressources supplémentaires.
Dans mon scénario cités dans la question ci-dessus, TaskCreationOptions.LongRunning ne force PAS un nouveau thread d'arrière-plan. Uniquement à l'aide de TaskScheduler.Par défaut n'.
La raison de soulever cette question, c'est que si quelqu'un dépend de ce détail de l'implémentation (que la tâche suivante sera exécutée sur un thread différent, puis celui en cours), il est possible de provoquer un blocage (bien connu comme "l'auto-blocage" ou "auto-attente de blocage") si l'hypothèse est violée.
OriginalL'auteur Trevor Elliott