Я считал, что потоки очень проблематичны. Какие альтернативы доступны? Что-то, что обрабатывает блокирование и материал автоматически?
Много людей рекомендует второстепенному рабочему, но я понятия не имею почему.
Кто-либо хочет объяснить "легкие" альтернативы? Пользователь сможет выбрать количество потоков для использования (в зависимости от их потребностей скорости и производительности компьютера).
Какие-либо идеи?
Подводя итог проблем с потоками:
Пример гонки: предположим, что два потока имеют общий доступ к некоторая память, где хранится число. Поток 1 считывает адрес памяти и сохраняет его в регистре ЦП. Поток 2 делает то же самое. Теперь поток 1 увеличивает число и записывает его обратно в память. Затем поток 2 делает то же самое. Конечный результат: число увеличивалось только на 1, в то время как оба потока пытались увеличить его. Результат таких взаимодействий зависит от времени. Хуже того, может показаться, что ваш код работает без ошибок, но однажды в синюю луну время не подходит, и случаются плохие вещи.
Чтобы избежать этих проблем, ответ прост: избегайте совместного использования записываемой памяти. Вместо этого используйте передачу сообщений для связи между потоками. Крайний пример - поместить потоки в отдельные процессы и обмениваться данными через TCP / IP-соединения или именованные каналы.
Другой подход заключается в совместном использовании структур данных только для чтения, поэтому языки функционального программирования могут так хорошо работать с несколькими потоками.
Я могу порекомендовать этот проект. Бассейн интеллектуальных резьбовых соединений
Описание проекта. Smart Thread Pool - это пул нитей, написанный на C#. Это гораздо более продвинутый, чем .NET встроенный пул потоков. Вот список функций пула потоков:
Не будут ли параметры параллельного программирования в .Net 4 «простым» способом использования потоков? Я не уверен, что бы я предложил для .Net 3.5 и более ранних версий ...
Эта ссылка MSDN на Центр разработчиков параллельных вычислений содержит ссылки на множество информации о программировании Parellel, включая ссылки на видео и т. д.
Каждый раз, когда вы вводите несколько потоков, каждый из которых запускается одновременно, вы открываете возможность для условий гонки . Чтобы избежать этого, вам, как правило, необходимо добавить синхронизацию, что добавляет сложности, а также увеличивает вероятность взаимоблокировок .
Многие инструменты упрощают эту задачу. В .NET есть несколько классов, специально предназначенных для облегчения работы с несколькими потоками, включая класс BackgroundWorker , который значительно упрощает выполнение фоновой работы и взаимодействие с пользовательским интерфейсом.
.NET 4 многое сделает, чтобы еще больше упростить эту задачу. Библиотека параллельных задач и PLINQ значительно упрощают работу с несколькими потоками.
Что касается вашего последнего комментария:
Пользователь сможет выбрать количество используемых потоков (в зависимости от их скорости и мощности компьютера).
Большинство подпрограмм в .NET построены на ThreadPool . В .NET 4 при использовании TPL рабочая нагрузка будет фактически масштабироваться во время выполнения для вас, избавляя вас от необходимости указывать количество используемых потоков. Однако есть способы сделать это сейчас.
В настоящее время вы можете использовать ThreadPool.SetMaxThreads , чтобы ограничить количество генерируемых потоков. В TPL вы можете указать ParallelOptions.MaxDegreesOfParallelism и передать экземпляр ParallelOptions в вашу процедуру для управления этим. Поведение по умолчанию масштабируется с увеличением количества потоков по мере добавления дополнительных ядер обработки, что обычно является лучшим поведением в любом случае.
Нитки не проблематичны, если вы понимаете, что вызывает с ними проблемы.
Например, если вы избегаете статики, вы знаете, какой API использовать (например, использовать синхронизированные потоки ), вы избежите многих проблем, которые возникают из-за их плохого использования.
Если многопоточность является проблемой (это может произойти, если у вас есть небезопасные/неуправляемые dll сторонних производителей, которые не могут поддерживать многопоточность. В этом случае можно создать meachism для постановки операций в очередь, т.е. хранить параметры действия в базе данных и просто прогонять их по одному. Это можно сделать в службе windows. Очевидно, что это займет больше времени, но в некоторых случаях это единственный вариант.
Потоки являются незаменимым инструментом для решения многих проблем, и зрелому разработчику необходимо знать, как их эффективно использовать. Но, как и многие другие инструменты, они могут вызвать некоторые очень трудные для поиска ошибки.
Не уклоняйтесь от некоторых из них только потому, что они могут вызвать проблемы, а вместо этого учитесь и практикуйте, пока не станете парнем, который будет работать с многопоточными приложениями.
Отличное место для начала - статья Джо Альбахари: http://www.albahari.com/threading/.
«Проблемная» - это не то слово, которое я бы использовал для описания работы с потоками. «Утомительный» - более подходящее описание.
Если вы новичок в многопоточном программировании, я бы посоветовал прочитать этот поток в качестве отправной точки. Он ни в коем случае не является исчерпывающим, но содержит полезную вводную информацию. Оттуда я бы продолжил изучать этот веб-сайт и другие сайты программирования в поисках информации, связанной с конкретными вопросами по цепочке, которые могут у вас возникнуть.
Что касается конкретных параметров потоковой передачи в C #, вот несколько советов о том, когда использовать каждый из них.
Это немного более высокоуровневый ответ, но он может быть полезен, если вы захотите рассмотреть другие альтернативы потоков. В любом случае, в большинстве ответов обсуждаются решения, основанные на потоках (или пулах потоков) или, возможно, задачах из .NET 4.0, но есть еще одна альтернатива, которая называется message-passing. Она успешно использовалась в Erlang (функциональный язык, используемый Ericsson). Поскольку функциональное программирование в наши дни становится все более распространенным (например, F#), я подумал, что могу упомянуть об этом. В genral:
Threads (или пулы потоков) обычно могут использоваться, когда у вас есть некоторые относительно длительные вычисления. Когда необходимо разделить состояние с другими потоками, это становится сложным (необходимо правильно использовать блокировки или другие примитивы синхронизации).
Задачи (доступно в TPL в .NET 4.0) очень легки - Вы можете разделить свою программу на тысячи задач, а затем дать время ее выполнения (она будет использовать оптимальное количество потоков). Если Вы можете написать свой алгоритм, используя задачи, а не потоки, то это звучит как хорошая идея - Вы можете избежать некоторой синхронизации при выполнении вычислений с меньшими шагами.
Деляративные подходы (PLINQ в .NET 4.0 - отличный вариант), если у вас есть какая-либо операция обработки данных более высокого уровня, которая может быть закодирована с помощью LINQ-примитивов, то вы можете использовать эту технику. Время выполнения автоматически распараллелит ваш код, так как в LINQ не указано, как именно должен оцениваться результат (вы просто говорите, какие результаты хотите получить).
Message-passing позволяет писать программу как параллельно выполняющиеся процессы, которые выполняют некоторые (относительно простые) задачи и общаются, посылая сообщения друг другу. Это замечательно, потому что Вы можете разделить некоторое состояние (отправить сообщения) без обычных проблем синхронизации (Вы просто отправляете сообщение, затем делаете что-то другое или ждете сообщений). Вот хорошее вступление к передаче сообщений на F# от Роберта Пикеринга.
Обратите внимание, что последние три техники вполне связаны с функциональным программированием - в функциональном программировании вы по-другому относитесь к программам - как к вычислениям, возвращающим результат (что облегчает использование Tasks). Также Вы часто пишете декларативный и более высокоуровневый код (что облегчает использование Declarative approaches).
Когда дело доходит до фактической реализации, F# имеет замечательную библиотеку, передающую сообщения прямо в базовых библиотеках. В C# можно использовать Concurrency & Coordination Runtime, что кажется немного "халтурным", но, наверное, тоже достаточно мощно (но может выглядеть слишком сложно).