簡體   English   中英

並發和多線程

[英]Concurrency and Multithreading

我對並發和多線程等主題不太熟悉。 事實上,在我的大部分網絡開發生涯中,我從未需要觸及這些主題。

我覺得這是一個重要的概念,特別是對於桌面應用程序,基本上任何其他不生成HTML的應用程序:)。

在閱讀了並發性的一點后,似乎在Go(谷歌編程語言)這樣的語言中得到了更好的支持,我不太明白為什么語言在並發等概念上比其他語言更好,因為它基本上是關於能夠fork()並行處理和計算東西,對吧? 編程是如何工作的?

多線程似乎是並發的一個分支,因為它允許您在同一進程下並行運行事物,盡管它似乎是特定於平台的如何實現它。

我想我的問題是, 為什么特定語言在並發性方面比其他語言更好?為什么fork()進程是一個更好的解決方案而不僅僅是使用線程?

好吧,有一件事,多個線程與多個進程不同,所以fork()實際上並不適用於此。

多線程/並行處理很難 首先,您必須弄清楚如何實際划分要完成的任務。 然后,您必須協調所有並行位,這些位可能需要相互通信或共享資源。 然后,您需要合並結果,在某些情況下,結果可能與前兩個步驟一樣困難。 我在這里簡化了,但希望你能得到這個想法。

所以你的問題是,為什么有些語言會更好? 好吧,有幾件事可以讓它變得更容易:

  • 優化的不可變數據結構。 您希望在並行處理中盡可能堅持不可變結構,因為它們更容易推理。 有些語言對這些語言有更好的支持,有些語言有各種優化,即能夠在沒有任何實際復制的情況下將集合拼接在一起,同時仍然強制執行不變性。 您可以隨時構建自己的結構,但如果語言或框架為您完成,則會更容易。

  • 同步原語和使用它們的便利性。 當不同的線程共享狀態時,它們需要同步,並且有許多不同的方法來實現這一點。 您獲得的同步原語數組越寬,您的任務最終將越容易。 如果您必須與關鍵部分而不是讀寫器鎖定同步,性能將受到影響。

  • 原子交易。 甚至比多種同步原語更好也不必使用它們。 數據庫引擎非常擅長這一點; 而不是你,程序員,必須弄清楚你需要鎖定哪些資源以及何時以及如何,你只需對編譯器或解釋器說,“這條線下的所有東西都需要一起發生,所以確保沒有其他人當我使用它時,它會被它弄亂。“ 引擎會為你找出鎖定。 你幾乎從來沒有在抽象編程語言中獲得這種簡單性,但你越接近越好。 將多個常見操作合並為一個的線程安全對象是一個開始。

  • 自動並行。 假設您必須遍歷一長串項目並以某種方式對其進行轉換,例如乘以50,000個10x10矩陣。 如果你能告訴編譯器那不是很好嗎: 嘿,每個操作都可以獨立完成,所以每個操作都使用一個單獨的CPU核心? 無需自己實際執行線程? 有些語言支持這種事情; 例如,.NET團隊一直致力於PLINQ。

這些只是一些可以使您在並行/多線程應用程序中更輕松的事情的例子。 我相信還有更多。

在不是為並發而設計的語言中,您必須依賴於低級系統調用並自己管理很多事情。 相比之下,為Erlang設計的編程語言(如Erlang)將提供隱藏低級細節的高級構造。 這樣可以更容易地推斷代碼的正確性,並且還可以生成更多可移植代碼。

此外,在為並發性設計的編程語言中,通常只有少數方法可以執行並發操作,從而實現一致性。 相反,如果編程語言不是為並發而設計的,那么不同的庫和不同的程序員將以不同的方式做事,這使得很難做出如何做的選擇。

這有點像自動垃圾收集的編程語言與沒有自動垃圾收集的編程語言之間的區別。 如果沒有自動化,程序員必須考慮很多實現細節。

多線程編程和多進程編程(即fork())之間的區別在於,多線程程序可能更高效,因為數據不必跨越進程邊界傳遞,但多進程方法可能更強大。

關於為什么fork()而不是線程的問題:當你使用單獨的進程時,你會自動分離地址空間。 在多線程程序中,線程使用它們(自然)共享內存進行通信是很常見的。 這是非常有效的,但也很難在線程之間獲得所有同步,這就是為什么有些語言在多線程方面比其他語言更好的原因:它們提供了更好的抽象來處理線程之間通信的常見情況。

使用單獨的進程,您可以在相同的范圍內遇到這些問題。 通常,您在進程之間建立通信以遵循某種形式的消息傳遞模式,這更容易實現。 (好吧,你也可以在進程之間使用共享內存,但這並不像消息傳遞那么常見。)在Unix系統上, fork()通常非常便宜,所以Unix中的並發程序的傳統設計使用進程,管道之間進行通信它們,但在進程創建是一項昂貴的操作的系統上,線程通常被認為是更好的方法。

我正在研究這個主題(現在:D),其中一個似乎是語言之間並發性的一個非常重要的區別就是語言對並發性的表達能力。

例如,C ++沒有本機支持並發性,它依賴於操作系統提供的功能。

Java是上面的一步,因為它有一些內置方法,而其他方法則留給操作系統(例如線程調度或優先級)。

相反 ,似乎是支持並發性的最佳編程語言之一是Ada,其實際上內置了一個完整的並發模型 (包括調度和優先級)。

為什么這很重要? 因為便攜性

使用具有良好並發性的語言表達能力允許您將並發程序帶到Windows,Linux或Mac,而不用擔心它的工作方式。 例如:在Windows,Linux或Mac中運行的Ada程序中,線程優先級將以相同的方式應用,而在Java或C ++中它們可能真的不同 (在某些操作系統中被忽略並在其他操作系統中應用)。

這就是我現在正在大學里學習的課程:)

Re:為什么有些語言的並發性比其他語言更好:這一切都取決於語言為程序員提供的工具。 某些語言(如C ++)為您提供對系統線程的低級訪問。 Java有各種各樣的庫,它們提供並發編程的結構,類似於設計模式(參見latch,barrier等)。 有些語言比其他語言更容易處理線程。 有些語言使您無法在線程之間共享狀態,這是錯誤的主要來源。

然后一些語言有不同的底層線程模型。 正如我所理解的,Python的線程模型使用單個系統線程並處理所有上下文切換本身,這不像它只是像單個Python指令一樣精細。

作為一個類比,它就像問為什么有些語言在處理正則表達式,搜索或進行復雜數學運算時最好只是移動位。

編輯:frunsi是正確的,Python線程是系統線程(顯然這是一個常見的誤解)。 我所指的問題是使用GIL或全局解釋器鎖來控制線程執行。 只有一個線程可以同時在Python解釋器中運行,並且上下文僅在指令之間切換。 我對Python多線程的了解主要來自本文: www.dabeaz.com/python/GIL.pdf 也許有點偏離主題,但仍然是一個很好的參考。

to fork is human to thread is divine:D

forking涉及內核並創建一個單獨的地址空間 - 意味着proc X和Y不能輕易共享並且需要使用IPC原語,並且創建一個線程允許進程同步,這比IPC更快,因為IPC涉及內核上下文切換進程和不必要的線程產量(涉及內核喚醒所述線程)。

但是,有很多原因導致不同的並發模型比其他模型更好。 我只是給你一般編程的粗略經驗。 例如,不分叉可能會危及可能通過分叉分離出來的邏輯(我喜歡這個詞) - 危及因為如果進程中的其他邏輯崩潰了,那么邏輯就會隨着進程而下降。

沒有一種語言比另一種語言更好,所有這些都與概念有關。 通過進程同時進行操作通常比線程消耗更多的資源(可以看作是輕量級進程),有些語言也很容易使用庫。 Java線程很容易使用,Posix線程(在unix上的C)有點復雜。

並發性基本上能夠以並行方式fork()進程和計算內容,就像內存管理基本上能夠調用malloc一樣。 這是故事的一部分,但不是全部。 能夠簡化與並發性相關的問題是兼容並發的語言之間的區別。

語言選擇取決於您要執行的應用程序。

您想創建一個高度可擴展的系統,有很多傳入的“請求”嗎? 然后Erlang可能是個不錯的選擇。 眾所周知,它非常適合“高度並發”的應用場景。

如果您想編寫一個典型的游戲並希望它使用現在通常可用的雙核或四核CPU,那么您將受到不同的決策(框架,引擎,庫,可用的硬件接口)。 在這種情況下,您將使用線程和線程池來卸載處理工作。 很可能你會使用一種消息隊列來在線程之間進行通信。

在(服務器端)Web開發中,您很可能已經獲得了並發編程的一些經驗! 也許你沒有意識到這一點,因為語言和給定的框架(可能是Apache和PHP)為你提供了一個可以減輕負擔的環境。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM