Вопрос по appdomain, deadlock, task-parallel-library, c# – Тупик при объединении удаленного взаимодействия и задач домена приложения

15

Мое приложение должно загружать плагины в отдельные домены приложений, а затем выполнять некоторый код внутри них асинхронно. Я'мы написали код для переносаTask в маршаллируемых типах:

static class RemoteTask
{
    public static async Task ClientComplete(RemoteTask remoteTask,
                                                  CancellationToken cancellationToken)
    {
        T result;

        using (cancellationToken.Register(remoteTask.Cancel))
        {
            RemoteTaskCompletionSource tcs = new RemoteTaskCompletionSource();
            remoteTask.Complete(tcs);
            result = await tcs.Task;
        }

        await Task.Yield(); // HACK!!

        return result;
    }

    public static RemoteTask ServerStart(Func func)
    {
        return new RemoteTask(func);
    }
}

class RemoteTask : MarshalByRefObject
{
    readonly CancellationTokenSource cts = new CancellationTokenSource();
    readonly Task task;

    internal RemoteTask(Func starter)
    {
        this.task = starter(cts.Token);
    }

    internal void Complete(RemoteTaskCompletionSource tcs)
    {
        task.ContinueWith(t =>
        {
            if (t.IsFaulted)
            {
                tcs.TrySetException(t.Exception);
            }
            else if (t.IsCanceled)
            {
                tcs.TrySetCancelled();
            }
            else
            {
                tcs.TrySetResult(t.Result);
            }
        }, TaskContinuationOptions.ExecuteSynchronously);
    }

    internal void Cancel()
    {
        cts.Cancel();
    }
}

class RemoteTaskCompletionSource : MarshalByRefObject
{
    readonly TaskCompletionSource tcs = new TaskCompletionSource();

    public bool TrySetResult(T result) { return tcs.TrySetResult(result); }
    public bool TrySetCancelled() { return tcs.TrySetCanceled(); }
    public bool TrySetException(Exception ex) { return tcs.TrySetException(ex); }

    public Task Task
    {
        get
        {
            return tcs.Task;
        }
    }
}

Это'используется как:

sealed class ControllerAppDomain
{
    PluginAppDomain plugin;

    public Task SomethingAsync()
    {
        return RemoteTask.ClientComplete(plugin.SomethingAsync(), CancellationToken.None);
    }
}

sealed class PluginAppDomain : MarshalByRefObject
{
    public RemoteTask SomethingAsync()
    {
        return RemoteTask.ServerStart(async cts =>
        {
            cts.ThrowIfCancellationRequested();
            return 1;
        });
    }
}

Но я'мы натолкнулись на загвоздку. Если вы посмотрите вClientComplete, там'это яTask.Yield()мы вставили Если я прокомментирую эту строку,ClientComplete никогда не вернется. Есть идеи?

Проверьте результаты поиска для "c # async deadlock ConfigureAwait " лайкstackoverflow.com/questions/13489065/... как я думаю, это было бы решением. Alexei Levenkov
@ user2477533: у меня нетсделано много с асинхронными вызовами между доменами приложений. Если ты можешьвернуть задание на ваш телефонный кодзатем вы можете ожидать его с нормальной семантикой потоков. Stephen Cleary
Это может быть полезно, если вы включили все вызовы для соответствующих потоков во время зависания. Andrew Arnott
@StephenCleary Я только что попробовал код на другом компьютере и могуТам тоже не воспроизвести. Интересно. Cory Nelson

Ваш Ответ

1   ответ
1

асинхронный метод который содержитЖдите и это управляется черезThreadPool которые могут выделить некоторыепереработанная нить.

СсылкаЛучшая практика для вызова ConfigureAwait для всего кода на стороне сервера

На самом деле, просто сделать ожидание может сделать это (поставить вас на другую тему). Как только ваш асинхронный метод попадает в ожидание, метод блокируется, но поток возвращается в пул потоков. Когда метод готов продолжить, любой поток вырывается из пула потоков и используется для возобновления метода.

Попробуйте упростить код, сгенерировать потоки для базовых случаев и производительность будет последней.

Кто бы ни проголосовал за этот ответ, было бы полезно оставить комментарий, объясняющий почему. Tim Long

Похожие вопросы