Czy istnieją przestarzałe praktyki programowania wielowątkowego i wieloprocesorowego, których nie powinienem już stosować?

36

Na początku FORTRAN i BASIC zasadniczo wszystkie programy były pisane przy pomocy instrukcji GOTO. W rezultacie powstał kod spaghetti, a rozwiązaniem było ustrukturyzowane programowanie.

Podobnie wskaźniki mogą mieć trudne do kontrolowania cechy w naszych programach. C ++ zaczęło się od wielu wskaźników, ale zalecane jest użycie referencji. Biblioteki takie jak STL mogą zmniejszyć część naszej zależności. Istnieją również idiomy do tworzenia inteligentnych wskaźników, które mają lepszą charakterystykę, a niektóre wersje C ++ pozwalają na odwołania i kod zarządzany.

Praktyki programowania, takie jak dziedziczenie i polimorfizm, wykorzystują wiele wskazówek za kulisami (tak jak w przypadku, gdy programowanie strukturalne generuje kod wypełniony instrukcjami rozgałęzienia). Języki takie jak Java eliminują wskaźniki i używają funkcji wyrzucania elementów bezużytecznych do zarządzania dynamicznie przydzielanymi danymi zamiast polegać na programistach w celu dopasowania wszystkich swoich nowych instrukcji usuwania i usuwania.

W swoim czytaniu widziałem przykłady programowania wieloprocesowego i wielowątkowego, które nie wykorzystują semaforów. Czy używają tego samego pod różnymi nazwami, czy też mają nowe sposoby strukturyzacji ochrony zasobów przed jednoczesnym użyciem?

Na przykład konkretnym przykładem systemu do programowania wielowątkowego z procesorami wielordzeniowymi jest OpenMP. Reprezentuje region krytyczny w następujący sposób, bez użycia semaforów, które wydają się nie być zawarte w środowisku.

th_id = omp_get_thread_num();
#pragma omp critical
{
  cout << "Hello World from thread " << th_id << '\n';
}

Ten przykład jest fragmentem: http://en.wikipedia.org/wiki/OpenMP

Alternatywnie, podobna ochrona wątków przed sobą za pomocą semaforów z funkcjami wait () i signal () może wyglądać następująco:

wait(sem);
th_id = get_thread_num();
cout << "Hello World from thread " << th_id << '\n';
signal(sem);

W tym przykładzie rzeczy są dość proste i wystarczy prosta recenzja, aby pokazać, że połączenia wait () i signal () są dopasowane, a nawet przy dużej współbieżności zapewnione jest bezpieczeństwo wątków. Ale inne algorytmy są bardziej skomplikowane i wykorzystują wiele semaforów (zarówno binarnych, jak i zliczających) rozmieszczonych w wielu funkcjach ze złożonymi warunkami, które mogą być wywoływane przez wiele wątków. Trudno poradzić sobie z konsekwencjami tworzenia impasu lub braku zapewnienia bezpieczeństwa wątków.

Czy takie systemy jak OpenMP eliminują problemy z semaforami?
Czy przenoszą problem gdzieś indziej?
Jak przekształcić mój ulubiony semafor za pomocą algorytmu, aby nie używać już semaforów?

DeveloperDon
źródło
O czym dokładnie mówisz? Co widziałeś?
svick,
4
Nie chciałem być niegrzeczny, ale mogłeś wyeliminować pierwsze trzy akapity. Naprawdę nie znoszą twojego pytania i przesadzają ze swoimi wnioskami i po prostu generują wiele argumentów.
dbracey,
1
Whoa, duża edycja. Odpowiedziałem nożem. Pytanie wciąż trochę wędruje przez GOTO, wskaźniki, dziedziczenie i polimorfizm, ale w mojej odpowiedzi odłożyłem te kwestie na bok i skupiłem się na pytaniu „przestarzałe praktyki”.
Stuart Marks

Odpowiedzi:

15

Czy istnieją równoległe techniki programowania i praktyki, których nie należy już stosować? Powiedziałbym tak .

Jedną z technik wczesnego programowania współbieżnego, która obecnie wydaje się rzadka, jest programowanie oparte na przerwie . Tak działał UNIX w latach siedemdziesiątych. Zobacz komentarz Lions dotyczący systemu UNIX lub Bach's Design systemu operacyjnego UNIX . W skrócie, technika polega na tymczasowym zawieszeniu przerwań podczas manipulowania strukturą danych, a następnie przywróceniu przerwań. Strona podręcznika użytkownika BSD spl (9)ma przykład tego stylu kodowania. Zauważ, że przerwania są zorientowane sprzętowo, a kod zawiera ukrytą zależność między rodzajem przerwania sprzętowego a strukturami danych powiązanymi z tym sprzętem. Na przykład kod, który manipuluje dyskowymi buforami we / wy, musi zawieszać przerwania na sprzęcie kontrolera dysku podczas pracy z tymi buforami.

Ten styl programowania stosowały systemy operacyjne na sprzęcie jednoprocesorowym. Znacznie rzadziej aplikacje radziły sobie z przerwaniami. Niektóre systemy operacyjne miały przerwania programowe i myślę, że ludzie próbowali zbudować na nich systemy wątków lub coroutine, ale nie było to zbyt rozpowszechnione. (Z pewnością nie w świecie UNIX.) Podejrzewam, że programowanie w stylu przerwania jest obecnie ograniczone do małych systemów wbudowanych lub systemów czasu rzeczywistego.

Semafory są postępem w stosunku do przerwań, ponieważ są konstrukcjami oprogramowania (niezwiązanymi ze sprzętem), zapewniają abstrakcje w stosunku do urządzeń sprzętowych oraz umożliwiają wielowątkowość i wieloprocesowość. Głównym problemem jest to, że są nieustrukturyzowane. Programista jest odpowiedzialny za utrzymanie relacji między każdym semaforem a strukturami danych, które chroni, globalnie w całym programie. Z tego powodu myślę, że gołe semafory są dziś rzadko używane.

Kolejnym małym krokiem naprzód jest monitor , który hermetyzuje mechanizmy kontroli współbieżności (blokady i warunki) z chronionymi danymi. Zostało to przeniesione do systemu Mesa (link alternatywny) , a stamtąd do Java. (Jeśli przeczytasz ten artykuł Mesa, zobaczysz, że blokady i warunki Javy są kopiowane niemal dosłownie z Mesa.) Monitory są pomocne w tym, że wystarczająco ostrożny i sumienny programista może bezpiecznie pisać współbieżne programy przy użyciu tylko lokalnego rozumowania o kodzie i danych w monitorze.

Istnieją dodatkowe konstrukcje bibliotek, takie jak te w java.util.concurrentpakiecie Java , które obejmują wiele wysoce współbieżnych struktur danych i konstrukcji puli wątków. Można je połączyć z dodatkowymi technikami, takimi jak ograniczanie nici i skuteczna niezmienność. Patrz Java Concurrency In Practice autorstwa Goetza i in. glin. do dalszej dyskusji. Niestety, wielu programistów wciąż rozwija własne struktury danych z blokadami i warunkami, kiedy naprawdę powinni używać czegoś takiego jak ConcurrentHashMap, w którym autorzy bibliotek już wykonali ciężkie podnoszenie.

Wszystko powyżej ma kilka istotnych cech: mają wiele wątków kontroli, które oddziałują na globalnie wspólny, zmienny stan . Problem polega na tym, że programowanie w tym stylu jest nadal bardzo podatne na błędy. Niewielki błąd jest dość łatwy do niezauważenia, co powoduje złe zachowanie, które jest trudne do odtworzenia i zdiagnozowania. Być może żaden programista nie jest „wystarczająco ostrożny i pracowity”, aby opracować w ten sposób duże systemy. Przynajmniej bardzo niewielu jest. Powiedziałbym więc, że należy w miarę możliwości unikać programowania wielowątkowego ze wspólnym, zmiennym stanem.

Niestety nie jest całkowicie jasne, czy można tego uniknąć we wszystkich przypadkach. Wiele programów wciąż jest wykonywanych w ten sposób. Byłoby miło, gdyby to zostało wyparte przez coś innego. Odpowiedzi Jarroda Robersona i Davidk01 wskazują na takie techniki, jak niezmienne dane, programowanie funkcjonalne, STM i przekazywanie wiadomości. Jest ich wiele do polecania, a wszystkie są aktywnie rozwijane. Ale nie sądzę, aby w pełni zastąpiły dobry, staromodny, wspólny, zmienny stan.

EDYCJA: oto moja odpowiedź na konkretne pytania na końcu.

Nie wiem dużo o OpenMP. Mam wrażenie, że może być bardzo skuteczny w przypadku bardzo równoległych problemów, takich jak symulacje numeryczne. Ale to nie wydaje się ogólnego zastosowania. Konstrukty semaforów wydają się dość niskie i wymagają od programisty utrzymywania relacji między semaforami a udostępnianymi strukturami danych, ze wszystkimi problemami, które opisałem powyżej.

Jeśli masz algorytm równoległy, który używa semaforów, nie znam żadnych ogólnych technik przekształcania go. Być może będziesz w stanie przekształcić go w obiekty, a następnie zbudować wokół niego abstrakcje. Ale jeśli chcesz użyć czegoś takiego jak przekazywanie wiadomości, myślę, że naprawdę musisz ponownie zrozumieć cały problem.

Znaki Stuarta
źródło
Dzięki, to świetna informacja. Przejrzę referencje i głębiej zanurzę się w koncepcjach, które wspomniałeś, które są dla mnie nowe.
DeveloperDon
+1 dla java.util.concurrent i zgodził się na komentarz - jest w JDK od 1.5 i rzadko, jeśli w ogóle go widzę, użyty.
MebAlone
1
Chciałbym, abyś podkreślił, jak ważne jest, aby nie toczyć własnych struktur, gdy już istnieją. Tyle, tyle błędów ...
corsiKa
Nie sądzę, aby można było powiedzieć: „Semafory są postępem w stosunku do przerwań, ponieważ są konstrukcjami oprogramowania (niezwiązanymi ze sprzętem) ”. Semafory zależą od procesora w celu wykonania instrukcji porównania i zamiany lub jej wariantów wielordzeniowych .
Josh Pearce,
@JoshPearce Oczywiście semafory są implementowane za pomocą konstrukcji sprzętowych, ale są abstrakcją niezależną od jakiejkolwiek konkretnej konstrukcji sprzętowej, takiej jak CAS, test-and-set, cmpxchng itp.
Stuart Marks
28

Odpowiedz na pytanie

Ogólny konsensus jest taki, że wspólnym stanem mutable jest Bad ™, a stanem niezmiennym jest Good ™, który okazuje się być dokładny i prawdziwy wielokrotnie w językach funkcjonalnych i imperatywnych.

Problem polega na tym, że imperatywne języki głównego nurtu po prostu nie są zaprojektowane do obsługi tego sposobu pracy, rzeczy nie zmienią się dla tych języków w ciągu nocy. To jest wada porównania do GOTO. Niezmienny stan i przekazywanie wiadomości to świetne rozwiązanie, ale nie jest to również panaceum.

Błędna przesłanka

To pytanie opiera się na porównaniach do błędnej przesłanki; taki GOTObył faktyczny problem i został powszechnie uznany przez Intergalatic Universal Board of Language Designers and Software Engineering Unions ©! Bez GOTOmechanizmu ASM w ogóle nie działałby. To samo z założeniem, że surowe wskaźniki są problemem w C lub C ++, a niektóre, jak inteligentne wskaźniki są panaceum, nie są.

GOTOnie był problemem, problem stanowili programiści. To samo dotyczy wspólnego stanu mutable . To samo w sobie nie stanowi problemu , problem stanowią programiści. Jeśli byłby sposób na wygenerowanie kodu, który używał współdzielonego stanu zmiennego w sposób, który nigdy nie miał żadnych warunków wyścigu ani błędów, to nie byłoby problemu. Podobnie jak w przypadku, gdy nigdy nie piszesz kodu spaghetti z GOTOkonstrukcjami równoważnymi, nie stanowi to również problemu.

Edukacja to panaceum

Programiści Idiot są jakie były deprecated, każdy popularny język wciąż ma GOTOkonstrukcję bezpośrednio lub pośrednio i to jest best practice, gdy stosowane właściwie w każdym języku, który ma tego typu konstrukcji.

PRZYKŁAD: Java ma etykiety i try/catch/finallyoba z nich działają bezpośrednio jako GOTOinstrukcje.

Większość programistów Java, z którymi rozmawiam, nawet nie wie, co immutabletak naprawdę oznacza poza nimi powtarzanie się the String class is immutablez oczami przypominającymi zombie. Zdecydowanie nie wiedzą, jak finalprawidłowo użyć słowa kluczowego, aby utworzyć immutableklasę. Jestem więc całkiem pewien, że nie mają pojęcia, dlaczego przekazywanie wiadomości za pomocą niezmiennych wiadomości jest tak wspaniałe i dlaczego stan wspólnego mutable nie jest tak świetny.

Społeczność
źródło
3
+1 Świetna odpowiedź, jasno napisana i wskazująca podstawowy wzór stanu zmiennego. IUBLDSEU powinien zostać memem :)
Dibbeke
2
GOTO jest słowem kodowym dla „proszę, nie, naprawdę, proszę, rozpocznij tutaj wojnę z ogniem, podwójny pies, odważę się”. To pytanie rozpala płomienie, ale tak naprawdę nie daje dobrej odpowiedzi. Wyróżnienia dotyczące programowania funkcjonalnego i niezmienności są świetne, ale w tych stwierdzeniach nie ma mięsa.
Evan Plaice,
1
To wydaje się być sprzeczną odpowiedzią. Najpierw mówisz „A jest zły, B jest dobry”, a następnie „idioci byli przestarzali”. Czy to samo nie dotyczy pierwszego akapitu? Czy nie mogę po prostu wziąć ostatniej części twojej odpowiedzi i powiedzieć: „Wspólny stan mutable jest najlepszą praktyką, jeśli jest właściwie stosowany w każdym języku”. Również „dowód” to bardzo mocne słowo. Nie powinieneś go używać, chyba że masz naprawdę mocne dowody.
luiscubal
2
Nie miałem zamiaru rozpętać wojny z płomieniami. Dopóki Jarrod nie zareagował na mój komentarz, myślał, że GOTO nie budzi kontrowersji i będzie działał dobrze w analogii. Kiedy napisałem pytanie, nie przyszło mi to do głowy, ale Dijkstra znajdował się na zerowym poziomie zarówno w GOTO, jak i semaforach. Edsger Dijkstra wydaje mi się gigantem i przypisano mu wynalezienie semaforów (1965) i wczesnej (1968) pracy naukowej na temat GOTO. Metoda rzecznictwa Dijkstry była często chrupiąca i konfrontacyjna. Kontrowersje / konfrontacja działały dla niego, ale chcę tylko pomysłów na temat możliwych alternatyw dla semaforów.
DeveloperDon
1
Wiele programów ma na celu modelowanie rzeczy, które w prawdziwym świecie są zmienne. Jeśli o 5:37 rano obiekt nr 451 utrzymuje stan czegoś w świecie rzeczywistym w tym momencie (5:37 rano), a stan rzeczy w świecie rzeczywistym następnie się zmienia, możliwe jest, że tożsamość obiektu reprezentująca stan rzeczy w świecie rzeczywistym musi być niezmienny (tj. rzecz zawsze będzie reprezentowana przez obiekt # 451) lub obiekt nr 451 będzie niezmienny, ale nie jedno i drugie. W wielu przypadkach niezmienność tożsamości będzie bardziej pomocna niż niezmienność obiektu # 451.
supercat
27

Najnowszą modą w kręgach akademickich wydaje się być Software Transactional Memory (STM), która obiecuje usunąć wszystkie włochate szczegóły programowania wielowątkowego z rąk programistów za pomocą wystarczająco inteligentnej technologii kompilatora. Za kulisami wciąż są zamki i semafory, ale jako programista nie musisz się o to martwić. Korzyści z takiego podejścia wciąż nie są jasne i nie ma oczywistych pretendentów.

Erlang używa przekazywania komunikatów i agentów do współbieżności i jest to prostszy model do pracy niż STM. Przy przekazywaniu wiadomości nie musisz się martwić o blokady i semafory, ponieważ każdy agent działa we własnym mini-wszechświecie, więc nie ma żadnych warunków wyścigowych związanych z danymi. Nadal masz dziwne przypadki na krawędzi, ale nie są one tak skomplikowane jak blokady na żywo i impasy. Języki JVM mogą korzystać z Akka i czerpać wszystkie korzyści z przekazywania wiadomości i aktorów, ale w przeciwieństwie do Erlanga, JVM nie ma wbudowanego wsparcia dla aktorów, więc pod koniec dnia Akka nadal korzysta z wątków i blokad, ale Ty jako programista nie musi się tym martwić.

Innym znanym mi modelem, w którym nie stosuje się blokad i wątków, jest stosowanie kontraktów futures, które są tak naprawdę kolejną formą programowania asynchronicznego.

Nie jestem pewien, ile tej technologii jest dostępne w C ++, ale są szanse, że jeśli zobaczysz coś, co nie używa jawnie wątków i blokad, będzie to jedna z powyższych technik zarządzania współbieżnością.

davidk01
źródło
+1 za nowy termin „włochate szczegóły”. LOL człowiek. Po prostu nie mogę przestać się śmiać z tego nowego terminu. Myślę, że od teraz będę używać „włochatego kodu”.
Saeed Neamati,
1
@ Saeed: Słyszałem już to wyrażenie, nie jest to rzadkie. Zgadzam się, że to zabawne :-)
Cameron
1
Dobra odpowiedź. Interfejs .NET CLI podobno ma również obsługę sygnalizacji (w przeciwieństwie do blokowania), ale jeszcze nie spotkałem się z przykładem, w którym całkowicie zastąpił blokowanie. Nie jestem pewien, czy liczy się asynchronizacja. Jeśli mówisz o platformach takich jak Javascript / NodeJs, w rzeczywistości są one jednowątkowe i tylko lepsze przy dużych obciążeniach IO, ponieważ są one znacznie mniej podatne na maksymalne limity zasobów (tj. W mnóstwie kontekstów jednorazowych). W przypadku obciążeń intensywnie obciążających procesor korzystanie z programowania asynchronicznego jest niewielkie.
Evan Plaice,
1
Ciekawa odpowiedź, wcześniej nie spotkałem przyszłości . Pamiętaj też, że wciąż możesz mieć zakleszczenie i blokadę w systemach przekazywania wiadomości, takich jak Erlang . CSP pozwala formalnie uzasadnić zakleszczenie i blokadę aktywności, ale samo w sobie nie zapobiega.
Mark Booth,
1
Dodałbym Zablokuj wolne i czekaj wolne struktury danych do tej listy.
stonemetal
3

Myślę, że chodzi głównie o poziomy abstrakcji. Dość często w programowaniu przydatne jest wyodrębnienie niektórych szczegółów w sposób bezpieczniejszy lub bardziej czytelny lub coś w tym rodzaju.

Dotyczy to struktur kontrolnych: ifs, forsi parzyste try- catchbloki są jedynie abstrakcjami nad gotos. Te abstrakcje są prawie zawsze przydatne, ponieważ zwiększają czytelność kodu. Ale zdarzają się przypadki, w których będziesz nadal musiał korzystać goto(np. Jeśli piszesz ręcznie asembler).

Dotyczy to również zarządzania pamięcią: inteligentne wskaźniki C ++ i GC są abstrakcjami w stosunku do surowych wskaźników i ręcznego usuwania / alokacji pamięci. A czasem te abstrakcje są nieodpowiednie, np. Gdy naprawdę potrzebujesz maksymalnej wydajności.

To samo dotyczy wielowątkowości: rzeczy takie jak futures i aktorzy to tylko abstrakcje nad wątkami, semaforami, muteksami i instrukcjami CAS. Takie abstrakcje mogą pomóc ci uczynić kod znacznie bardziej czytelnym, a także pomogą ci uniknąć błędów. Ale czasami są po prostu nieodpowiednie.

Powinieneś wiedzieć, jakie masz dostępne narzędzia i jakie są ich zalety i wady. Następnie możesz wybrać poprawną abstrakcję dla swojego zadania (jeśli istnieje). Wyższe poziomy abstrakcji nie umniejszają niższych poziomów, zawsze będą przypadki, w których abstrakcja nie jest odpowiednia, a najlepszym wyborem jest użycie „starej drogi”.

svick
źródło
Dzięki, wychwytujesz analogię, a ja nie mam z góry założonego pomysłu, a nawet siekiery, żeby się zastanowić, czy semafory odpowiedzi WRT są takie, że są przestarzałe. Większe pytania są dla mnie, czy istnieją lepsze sposoby iw systemach, w których semafory wydają się nie mieć czegoś ważnego i czy nie byłyby w stanie wykonać pełnego zakresu algorytmów wielowątkowych.
DeveloperDon
2

Tak, ale prawdopodobnie nie spotkasz niektórych z nich.

W dawnych czasach powszechne było stosowanie metod blokowania (synchronizacja barier), ponieważ pisanie dobrych muteksów było trudne. Nadal można zobaczyć ślady tego w różnych rzeczach, ponieważ niedawne korzystanie z nowoczesnych bibliotek współbieżności zapewnia znacznie bogatszy i dokładnie przetestowany zestaw narzędzi do równoległości i koordynacji między procesami.

Podobnie starszą praktyką było pisanie torturującego kodu, aby można było dowiedzieć się, jak go zrównoleglić ręcznie. Ta forma optymalizacji (potencjalnie szkodliwej, jeśli się pomylisz) również w dużej mierze wyszła poza okno wraz z pojawieniem się kompilatorów, które robią to za Ciebie, w razie potrzeby rozwijając pętle, przewidując następujące gałęzie itp. To jednak nie jest nowa technologia , co najmniej 15 lat na rynku. Korzystanie z takich rzeczy, jak pule wątków, pozwala także ominąć niektóre naprawdę podstępne kody z przeszłości.

Być może przestarzałą praktyką jest samodzielne pisanie kodu współbieżności zamiast korzystania z nowoczesnych, dobrze przetestowanych bibliotek.

Alex Feinman
źródło
Dzięki. Wygląda na to, że istnieje duży potencjał do korzystania z programowania współbieżnego, ale może to być puszka Pandory, jeśli nie będzie używana w zdyscyplinowany sposób.
DeveloperDon
2

Grand Central Dispatch firmy Apple to elegancka abstrakcja, która zmieniła moje myślenie o współbieżności. Z mojego skromnego doświadczenia wynika, że ​​skupienie się na kolejkach upraszcza implementację logiki asynchronicznej o rząd wielkości.

Kiedy programuję w środowiskach, w których jest on dostępny, zastąpił większość moich zastosowań wątków, blokad i komunikacji między wątkami.

orip
źródło
1

Jedną z głównych zmian w programowaniu równoległym jest to, że procesory są niesamowicie szybsze niż wcześniej, ale aby osiągnąć tę wydajność, wymagają ładnie zapełnionego bufora. Jeśli spróbujesz uruchomić kilka wątków jednocześnie, ciągle między nimi przełączając się, prawie zawsze unieważniasz pamięć podręczną dla każdego wątku (tj. Każdy wątek wymaga różnych danych do działania) i kończysz się zabijaniem wydajności znacznie bardziej niż ty przyzwyczajony do wolniejszych procesorów.

Jest to jeden z powodów, dla których frameworki asynchroniczne lub oparte na zadaniach (np. Grand Central Dispatch lub Intel TBB) są bardziej popularne, uruchamiają zadania kodu 1 na raz, kończąc je przed przejściem do następnego - jednak trzeba je zakodować każde zadanie zajmuje niewiele czasu, chyba że chcesz zepsuć projekt (tzn. zadania równoległe są naprawdę ustawione w kolejce). Zadania intensywnie wykorzystujące procesor są przekazywane do alternatywnego rdzenia procesora, a nie przetwarzane w jednym wątku, przetwarzając wszystkie zadania. Łatwiej jest także zarządzać, jeśli nie dzieje się tak naprawdę przetwarzanie wielowątkowe.

gbjbaanb
źródło
Fajnie, dziękuję za odniesienia do technologii Apple i Intel. Czy twoja odpowiedź wskazuje wyzwania związane z zarządzaniem wątkiem od powinowactwa do rdzenia? Niektóre problemy z wydajnością pamięci podręcznej zostały złagodzone, ponieważ procesory wielordzeniowe mogą powtarzać pamięci podręczne L1 na rdzeń? Na przykład: software.intel.com/en-us/articles/… Szybka pamięć podręczna dla czterech rdzeni z większą liczbą trafień w pamięci podręcznej może być ponad czterokrotnie szybsza niż jeden rdzeń z większą liczbą braków pamięci podręcznej dla tych samych danych. Mnożenie macierzy może. Losowe planowanie 32 wątków na 4 rdzeniach nie może. Użyjmy powinowactwa i uzyskaj 32 rdzenie.
DeveloperDon
tak naprawdę nie jest to ten sam problem - powinowactwo rdzenia odnosi się tylko do problemu, w którym zadanie jest odbijane od rdzenia do rdzenia. To samo dotyczy sytuacji, gdy zadanie zostanie przerwane, zastąpione nowym, a następnie oryginalne zadanie będzie kontynuowane na tym samym rdzeniu. Intel mówi tam: trafienia w pamięć podręczną = szybkie, brakujące w pamięci podręcznej = wolne, niezależnie od liczby rdzeni. Myślę, że próbują przekonać cię do kupowania swoich żetonów zamiast AMD :)
gbjbaanb