Member 10285969 Ответов: 2

Многозадачность с таймерами


пожалуйста, помогите мне понять, что я думал, что ответ просто возвращается к тому же самому. Я программист-самоучка, который мало что знает. Таймер все время работает одно и то же, потому что он использует поток пользовательского интерфейса. Пожалуйста, как мне запустить два таймера, чтобы взять из списка и просматривать веб-страницы, используя информацию из списка?
Моя проблема заключается в том, что все они используют один и тот же предмет, и это не очень хорошо из-за повторения, и я даже не знаю, как направить "timers.timer" и "threading.timer" в этот вопрос, чтобы выручить меня. Пожалуйста, ваша помощь очень нужна.

Что я уже пробовал:

просто вводя в webbrowser bt с помощью synclock с тремя таймерами работающими одновременно bt они похоже используют один и тот же элемент из списка потому что они работают в потоке пользовательского интерфейса

Slacker007

Не слишком ли сложна эта задача для новичка? Есть над чем подумать.

Member 10285969

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

Gerry Schmitz

Вы получаете "решения"; но поскольку вы не ясно дали понять, почему вы думаете, что вам нужны 3 таймера, вы, вероятно, "решаете" неправильную "проблему".

Обычно существует более одного способа решить что-то, причем некоторые решения намного лучше, чем другие; но не тогда, когда вы не ясны в первую очередь.

CHill60

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

2 Ответов

Рейтинг:
1

Graeme_Grant

Вот альтернативный метод, основанный на асинхронных вызовах с использованием Асинхронный...Ожидать[^].

Асинхронный...Await использует пул потоков для управления многозадачностью. Количество потоков, выполняемых одновременно, зависит от процессора и количества ядер. Если вы хотите изменить настройку по умолчанию, то в следующей документации будет объяснено, как это сделать: потоки ThreadPool.Метод SetMinThreads(Int32, Int32) (System.Продевать Нитку) | Майкрософт Документы[^]

То служба WebClient[^] класс DownloadStringTaskAsync[^] метод, который мы можем использовать. Мы можем принудительно запустить метод из потока пользовательского интерфейса, вызвав ConfigureAwait(false)[^].

Чтобы помочь нам визуализировать, как это работает, давайте обернем вызов в метод:

private static async Task<Tuple<string, string>> GetUrlAsync(Uri url)
{
    Console.WriteLine("thisIsAsyncStart: " 
        + Thread.CurrentThread.ManagedThreadId);

    // make our call on another thread
    var result = await new WebClient()
        .DownloadStringTaskAsync(url).ConfigureAwait(false);

    Console.WriteLine("thisIsAsyncEnd: " + Thread.CurrentThread.ManagedThreadId);

    // return both the uri passed and the data returned
    return new Tuple<string, string>(url.ToString(), result);

    // we return to the UI thread when we exit this method
}

Далее, нам нужно несколько URI для вызова:
private static List<Uri> urls = new List<Uri>()
    {
        new Uri("https://www.codeproject.com", UriKind.Absolute),
        new Uri("https://apple.com", UriKind.Absolute),
        new Uri("https://xamarin.com", UriKind.Absolute),
        new Uri("https://nokia.com", UriKind.Absolute),
        new Uri("https://samsung.com", UriKind.Absolute),
        new Uri("https://www.microsoft.com", UriKind.Absolute),
        new Uri("https://www.codeproject.com", UriKind.Absolute),
        new Uri("https://apple.com", UriKind.Absolute),
        new Uri("https://xamarin.com", UriKind.Absolute),
        new Uri("https://nokia.com", UriKind.Absolute),
        new Uri("https://samsung.com", UriKind.Absolute),
        new Uri("https://www.microsoft.com", UriKind.Absolute),
        new Uri("https://www.codeproject.com", UriKind.Absolute),
        new Uri("https://apple.com", UriKind.Absolute),
        new Uri("https://xamarin.com", UriKind.Absolute),
        new Uri("https://nokia.com", UriKind.Absolute),
        new Uri("https://samsung.com", UriKind.Absolute),
        new Uri("https://www.microsoft.com", UriKind.Absolute),
        new Uri("https://www.codeproject.com", UriKind.Absolute),
        new Uri("https://apple.com", UriKind.Absolute),
        new Uri("https://xamarin.com", UriKind.Absolute),
        new Uri("https://nokia.com", UriKind.Absolute),
        new Uri("https://samsung.com", UriKind.Absolute),
        new Uri("https://www.microsoft.com", UriKind.Absolute),
        new Uri("https://www.codeproject.com", UriKind.Absolute),
        new Uri("https://apple.com", UriKind.Absolute),
        new Uri("https://xamarin.com", UriKind.Absolute),
        new Uri("https://nokia.com", UriKind.Absolute),
        new Uri("https://samsung.com", UriKind.Absolute),
        new Uri("https://www.microsoft.com", UriKind.Absolute),
    };

Теперь есть два способа, которые я продемонстрирую, управляя несколькими задачами одновременно.

1. WhenAll[^] - Создает задачу, которая будет завершена, когда все объекты задачи в массиве будут завершены
private static async Task RunWhenAllAsync()
{
    var tasks = new List<Task<Tuple<string, string>>>();

    foreach (var url in urls)
    {
        tasks.Add(GetUrlAsync(url));
    }

    await Task.WhenAll(tasks.ToArray());

    foreach (var task in tasks)
    {
        var result = task.Result;
        Console.WriteLine($"id: {task.Id} | url {task.Result.Item1} > length: {task.Result.Item2.Length}");
    }
}

Выход:
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncStart: 1
thisIsAsyncEnd: 13
thisIsAsyncEnd: 11
thisIsAsyncEnd: 13
thisIsAsyncEnd: 13
thisIsAsyncEnd: 11
thisIsAsyncEnd: 16
thisIsAsyncEnd: 11
thisIsAsyncEnd: 12
thisIsAsyncEnd: 16
thisIsAsyncEnd: 15
thisIsAsyncEnd: 12
thisIsAsyncEnd: 12
thisIsAsyncEnd: 13
thisIsAsyncEnd: 11
thisIsAsyncEnd: 16
thisIsAsyncEnd: 11
thisIsAsyncEnd: 11
thisIsAsyncEnd: 16
thisIsAsyncEnd: 14
thisIsAsyncEnd: 14
thisIsAsyncEnd: 13
thisIsAsyncEnd: 12
thisIsAsyncEnd: 15
thisIsAsyncEnd: 14
thisIsAsyncEnd: 12
thisIsAsyncEnd: 13
thisIsAsyncEnd: 14
thisIsAsyncEnd: 11
thisIsAsyncEnd: 15
thisIsAsyncEnd: 11
id: 1 | url https://www.codeproject.com/ > length: 96485
id: 3 | url https://apple.com/ > length: 53646
id: 5 | url https://xamarin.com/ > length: 149548
id: 7 | url https://nokia.com/ > length: 73246
id: 9 | url https://samsung.com/ > length: 106147
id: 11 | url https://www.microsoft.com/ > length: 1020
id: 13 | url https://www.codeproject.com/ > length: 96479
id: 15 | url https://apple.com/ > length: 53646
id: 17 | url https://xamarin.com/ > length: 149548
id: 19 | url https://nokia.com/ > length: 73246
id: 21 | url https://samsung.com/ > length: 106147
id: 23 | url https://www.microsoft.com/ > length: 1020
id: 25 | url https://www.codeproject.com/ > length: 96485
id: 27 | url https://apple.com/ > length: 53646
id: 29 | url https://xamarin.com/ > length: 149548
id: 31 | url https://nokia.com/ > length: 73246
id: 33 | url https://samsung.com/ > length: 106147
id: 35 | url https://www.microsoft.com/ > length: 1020
id: 37 | url https://www.codeproject.com/ > length: 96485
id: 39 | url https://apple.com/ > length: 53646
id: 41 | url https://xamarin.com/ > length: 149548
id: 43 | url https://nokia.com/ > length: 73246
id: 45 | url https://samsung.com/ > length: 106147
id: 47 | url https://www.microsoft.com/ > length: 1020
id: 49 | url https://www.codeproject.com/ > length: 96485
id: 51 | url https://apple.com/ > length: 53646
id: 53 | url https://xamarin.com/ > length: 149548
id: 55 | url https://nokia.com/ > length: 73246
id: 57 | url https://samsung.com/ > length: 106147
id: 59 | url https://www.microsoft.com/ > length: 1020

Выгоды:

  • код очень прост
  • поток пользовательского интерфейса не будет заблокирован
  • задачи выполняются асинхронно в отдельных потоках пользовательского интерфейса
  • результаты отображаются в том порядке, в котором были созданы задачи, а не в том порядке, в котором они были выполнены

Недостатки:

  • выполнение будет ждать, пока все задачи не будут завершены
  • пользователь не получит никакой обратной связи о прогрессе

2.

Member 10285969

сайт использует javascript, что является недостатком.

Graeme_Grant

Так ты хочешь сделать соскоб страницы? приведенное выше решение будет делать то, что вы хотите получить на странице...

Member 10285969

это одна страница, где вы вводите строки, которые приносят результат с помощью javascript

Member 10285969

я попробовал fiddler, но не получил ничего значимого, но попробую еще раз и дам вам знать результат.

Graeme_Grant

для более высокого уровня ... используйте инструменты вашего веб-браузера "F12", там тоже есть анализатор трафика

Member 10285969

как я могу написать тебе наедине? Я хочу дать вам сайт, чтобы вы посмотрели, можете ли вы помочь мне захватить его почтовый запрос, потому что для меня это невозможно. Либо зашифровано, и я не хочу выставлять это публично. Пожалуйста.
Dnt knw, если вы можете удалить комментарий..

Graeme_Grant

Это отдельный вопрос к тому, на который уже дан ответ. Пожалуйста, отметьте этот ответ как ответ, который касается загрузки нескольких страниц в фоновом режиме. Вопрос, на который вы хотите получить ответ, должен быть открыт как новый вопрос.

Richard Deeming

NB: Task.WhenAll имеет перегрузку, которая занимает IEnumerable<Task> так что в этом нет никакой необходимости. .ToArray() вызов:

await Task.WhenAll(tasks);

Он также имеет перегрузку для задач с возвращаемым значением:
private static async Task RunWhenAllAsync()
{
    IEnumerable<Tuple<string, string>> tasks = urls.Select(GetUrlAsync);
    Tuple<string, string>[] results = await Task.WhenAll(tasks);
    
    foreach (Tuple<string, string> result in results)
    {
        Console.WriteLine($"url {result.Item1} > length: {result.Item2.Length}");
    }
}

Graeme_Grant

Я не люблю использовать WhenAll и только включил его в качестве примера. Спасибо, что указали на это для операции и других. :)

Рейтинг:
0

OriginalGriff

Если вы специально не запускаете новый поток, вся обработка происходит в исходном потоке пользовательского интерфейса. А если вы все же запустите дополнительные потоки, они не смогут напрямую получить доступ к каким-либо компонентам пользовательского интерфейса (включая элементы управления WebBrowser) без возникновения исключения перекрестной потоковой передачи.

Вместо того чтобы использовать веб-браузеры и таймеры, используйте BackgroundWorker[^] (Они являются отдельным потоком, но они позволяют легко передавать результаты потоку пользовательского интерфейса через события прогресса / выхода) и использовать класс WebClient[^] для взаимодействия с веб-страницей в каждом потоке.

Если фоновые потоки должны ждать определенное время, вы можете использовать Нить.Спать[^] чтобы сделать это без необходимости таймеров.


Member 10285969

это хорошая идея, но неудача заключается в том, что веб-сайт, с которым я работаю, в основном использует javascript для получения нужных мне результатов, поэтому я иду на webbrowser с его событием click.

Другое дело, что при использовании таймера вы гарантируете, что он доставляет или инициирует щелчок, чтобы вывести результат, включив "timer1.stop ()" в начале события тика, так ли это с backgroundworker? Мне очень нравится эта идея, потому что я мог бы использовать ее для обработки события webbrowser click.