Sito Eratostenesa współbieżnie.

Sito Eratostenesa współbieżnie.
0

Cześć,

Chciałem porównać czasy obliczania sita Eratostenesa dla różnej liczby wątków. Napisałem następujący program, ale nie działa tak jak trzeba.

Kopiuj
import java.util.HashMap;

public class Sieve implements Runnable{
	private HashMap<Integer,Boolean> array = new HashMap<Integer,Boolean>();
	private int counter = 1;
	private int x;
	public void run(){
	    while(counter < x-1){
	        do{
	            counter++;
	        }
	        while( array.get(counter));
	        int tmp = counter;
	        for(int i = tmp; i < array.size(); i+=tmp){
	            if( i!= tmp)
	                array.put(i,true);
	        }
	        try{
	        Thread.sleep(0L, 1);
	        }
	        catch (Exception e){}
	    }
	}

	public void setArray(int x){
	    this.x = x;
	    for(int i = 2; i < x; i++)
	        array.put(i, false);
	}
	public void printArray(){

	    for(int i = 2; i < array.size();i++){
	        if( !array.get(i))
	        System.out.println(i);

	    }
	}
} 

Klasa główna

Kopiuj
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
	public static void main(String[] args) throws InterruptedException{
		Sieve task = new Sieve();
		task.setArray(50000);
		Long beg = new Date().getTime();
		ExecutorService exec = Executors.newCachedThreadPool();
		for(int i = 0; i < 1;i++){
			exec.execute(task);
		}
		exec.shutdown();
		Long sleep = 300L;
		Thread.sleep(sleep);
		task.printArray();
		System.out.println("Time is "+(new Date().getTime()-beg-sleep));
	}
}

Problem polega na tym, że wraz ze wzrostem liczby wątków czasy wykonania nie zmniejszają się. Czasami wręcz zwiększają się... Czym może to być spowodowane?
Dodatkowo zauważyłem, że spory czas po zakończeniu obliczeń wątek DestroyJavaVM bardzo długo "pracuje". Czyżby to Garbage Collector sprzątał po HashMapie?

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Ja chyba czegoś nie rozumiem. Przecież w u ciebie w tym kodzie odpalasz zwykłe seryjne sito, tylko że robisz to wiele razy. Ergo nie dziwota że działa wolniej -> procesor musi dzielić czas pomiędzy wątki. Spowolnienie zapewne jest liniowe i takie też być powinno...


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
0

Dodałem

Kopiuj
System.out.print(tmp+" id="+Thread.currentThread().getId()+"\n");

do metody run()
Wyniki prezentują się następująco

Kopiuj
2 id=8
3 id=9
5 id=10
7 id=8
11 id=11
13 id=10
17 id=9
19 id=8
23 id=11
29 id=10
31 id=9
37 id=8
41 id=11
43 id=10
47 id=9
53 id=8
59 id=9
61 id=8
67 id=11
71 id=10
73 id=9
79 id=8
83 id=11
89 id=10
97 id=9
Time is 5

Skoro kolejne liczby są "wykreślane" przez kolejne wątki, to dlaczego te wątki nie działają współbieżnie?

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Dopiero teraz zobaczyłem co ty robisz. Słyszał kiedy o takich rzeczach jak synchronizacja albo race condition? To doczyta. Jakby to chciaż była ConcurrentHashMap...
Poza tym ile masz rdzeni procesora? Jak odpalisz ten kod to ile rdzeni zabiera JVM?


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 2x, ostatnio: Shalom
0

Słyszał i czytał, ale widocznie za mało, bo nie bardzo wiem jak to tutaj zastosować. Jeżeli dam dodam parametr synchronized do metody run, to nie będzie wtedy współbieżności. Bez bicia przyznam, że nie wiem jak inaczej mógłbym to usprawnić. Początkowo, program usuwał elementy z HashMapy( żeby nie sprawdzać 6 dwa razy itp), ale nie wiedziałem jak rozwiązać problem synchronizacji.
Rdzenie mam 4, ale nie wiem jak sprawdzić ile z nich jest wykorzystywanych przez JVM( JVisualVM ma takie możliwości?)

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

No ewidentnie za mało skoro "synchronizujesz" to sobie przez sleep() (którego być tu nie powinno!). Albo użyj ConcurrentHashMap albo synchronizuj samą operację na mapie tam gdzie ją wykonujesz, tzn

Kopiuj
synchronized(array){
  operacja_na_mapie
}

A tego sleepa wywal. Powinno działać lepiej...


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
0

Synchronizacja synchronizacją, a tu się spory błąd wkradł i tak sobie czekał i czekał. Tym błędem było złe liczenie czasu. Zamiast liczyć czas, wykonywania wątków to mój program liczył czas wypisywania wyników.
Aby realnie mierzyć czas wykonywania programu dodałem do klasy Sieve zmienną threads. Którą później inkrementuję i dekrementuję w odpowiednich miejscach:

Kopiuj
 public void run(){
    threads++;
    while(counter < x-1){
    ...
    }
    threads--;
}

W klasie Main dodałem coś takiego.

Kopiuj
        Long time = 0L;
        while(true){
            if(task.threads == 0){
                time = new Date().getTime()-beg;
                break;
            }
            else 
                Thread.sleep(10);
           }

        task.printArray();
        System.out.println("Time is "+time);

Czyli sprawdzam w pętli czy wątki poboczne się zakończyły( a przynajmniej ja to tak rozumiem). Następnie wypisuję zawartość mapy i czas. Niestety nie działa to tak jak chciałem. Ostatnim poleceniem w metodzie run jest threads--; a mimo to wątek wydaje się liczyć dłużej. Czym może to być spowodowane?
Wyniki dla powyższego kodu i dla kodu po sleepie:

Kopiuj
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Time is 5



Po sleepie
2
3
5
7
11
13
17
19
0

Napisałem od początku metodę run. W ogólnym odczuciu program działa wolniej, ale przynajmniej współbieżnie. Niestety dla dużych zakresów liczb( 20 000). Wyniki są błędne, jakieś sugestie czemu?

Kopiuj
public void run() {
		synchronized(this){
			threads++;
		}
		List<Integer> list = new ArrayList<Integer>();
		synchronized (list) {
			while (counter < Math.sqrt(x)){
				// 
				list.add(counter++);
				try {
					Thread.sleep(0,1);
				} catch (InterruptedException e) {}
			}
		}
		Collections.sort(list);
		for (Integer it : list) {
			int n = it.intValue();
			for (int i = n; i < x; i += n) {
				if (array.get(i) && i == n)
					break;
				if( i > n)
					array.put(i, true);
			}
		}
		synchronized(this){
			threads--;
		}
	}
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Bo wykonujesz operacje na kolekcji poza sekcją krytyczną? o_O Robisz "sort" na liście poza blokiem synchronizacji i jak to niby ma działać? W ogóle zresztą modyfikujesz tam tą tablicę co jest jakimś WTFem. Nie lecą ci czasem ConcurrentModificationException? ;]


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
0
Shalom napisał(a):

W ogóle zresztą modyfikujesz tam tą tablicę co jest jakimś WTFem. Nie lecą ci czasem ConcurrentModificationException? ;]

Nie leci. Dlaczego WTF?

Ogólnie mój pomysł był następujący:
W pierwszej pętli while w każdym wątku wrzucam do listy kolejne liczby z podanego zakresu( np 2-200).
Po każdym addzie robię Thread.sleepa(* Thread.yield*() nie zmienia mi wątków1) aby kolejne liczby były dodawane do list kolejnych wątków.
czyli:

Ze sleepem Z yieldem
2 T-1 2 T-1
3 T-2 3 T-1
4 T-3 4 T-1
5 T-1 5 T-1
6 T-2 6 T-1
etc
Później w pętli każdy wątek sprawdza swoją listę liczb( co wykonuje współbieżnie) i zaznacza liczby złożone.

Problemem jest fakt, że korzystanie ze sleepa znacząco spowalnia program. Niekorzystanie ze sleepa nie skraca czasu przy zwiększaniu liczby wątków.
Ze sleepem:
2-2000, 1 watek, czas: 2242
2-2000, 4 wątki, czas:589
Z yieldem
2-200000, 1 watek, czas: 496
2-200000, 4 wątki, czas: 513

1 Czy może to wynikać z używania* CachedThreadPool*?

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:44 minuty
1
Kopiuj
public void run() {
                synchronized(this){
                        threads++;
                }
                List<Integer> list = new ArrayList<Integer>();
                synchronized (list) {
                        while (counter < Math.sqrt(x)){
                                // 
                                list.add(counter++);
                                try {
                                        Thread.sleep(0,1);
                                } catch (InterruptedException e) {}
                        }
                }

To nie jest WTF, to jest ROTFL.

Robisz lokalną zmienną list i się na niej synchronizujesz? No człowieku, przecież ta lista jest lokalna dla każdego wątku. To na zmiennej counter powinieneś się synchronizować.

Z tym, że synchronizowanie się na prymitywach jest trochę bez sensu, bo od Javy 5 mamy takie bajery: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/atomic/package-summary.html

Collections.sort(list);
Czy przypadkiem nie sortujesz listy, która już jest posortowana? counter leci tylko w górę, a ty dodajesz kolejne wartości counter. No chyba, że masz sieczkę przez brak synchronizacji na counter.

Kopiuj
                for (Integer it : list) {
                        int n = it.intValue();
                        for (int i = n; i < x; i += n) {
                                if (array.get(i) && i == n)
                                        break;
                                if( i > n)
                                        array.put(i, true);
                        }
                }

To już jest fraktalny WTF.

Po pierwsze zakładasz, że pola w mapie będą aktualizowane w określonym porządku, a przecież masz niesynchronizowane wątki.
Po drugie ta pętla nie ma nic wspólnego z sitem Erastotenesa. Sito działa mniej więcej tak:

  1. ustaw wszystkie liczby na złożone (u ciebie to false)
  2. począwszy od 2 rób następującą rzecz:
  • wykreśl wszystkie wielokrotności aktualnej liczby (jako optymalizacja - jeśli aktualna liczba jest złożona, to można pominąć ten krok),
  • przejdź do kolejnej liczby,
    A więc to ma być zagnieżdżenie typu: for -> if -> for, a nie for -> for -> if.

Zresztą na Wiki masz kod, który to potwierdza:

Kopiuj
        boolean[] numbersTable = new boolean[n+1];
        for(int i = 2; i*i <= n; i++)
        {
            if (numbersTable[i] == true)
                continue;
            for (int j = 2 * i ; j <= n; j += i)
                numbersTable[j] = true;
 
        }

"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
0

Wprowadziłem zmiany w metodzie run:

  • Zamieniłem counter na AtomicInteger
  • Wywaliłem sortowanie listy
  • Przebudowałem pętle z sitem.
Kopiuj
private AtomicInteger counter = new AtomicInteger(2);

	public void run() {
		List<Integer> list = new ArrayList<Integer>();	
			while (counter.get() < x) {
				list.add(counter.get());
				counter.incrementAndGet();
			//	 try {
				// Thread.sleep(1);
				// } catch (InterruptedException e) {}
				// Thread.yield();
		}
		for (Integer it : list) {
			  System.out.println(it.intValue());
			int n = it.intValue();
			if (array.get(n))
				continue;
			for (int i = 2 * n; i <= x; i += n) 
					array.put(i, true);
		}
	}

Zrobiłem też drugą wersję, która nie korzysta z list. Zamiast listy, używam metody synchronizowanej, która zwraca mi aktualną wartość.

Kopiuj
private int counter = 2;

	public void run() {
		int n = 0;
		while(true){
			n = getCounter();
			if( n == -1)
				break;
			if (array.get(n))
				continue;
			for (int i = 2 * n; i <= x; i += n) {
					array.put(i, true);
			}
		}
	}
	private synchronized int getCounter(){
		if( counter < x)
			return counter++;
		else return -1;
	}

Niestety w obu przypadkach, zwiększenie liczby wątków nie zwiększa prędkości działania. Jakieś sugestie dlaczego?

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:44 minuty
0

Algorytm dalej jest niedeterministyczny, wystarczy na początku każdej iteracji wstawić sleep(random) i da złe wyniki. To że działa (o ile rzeczywiście działa) jest łutem szczęścia.

Niestety w obu przypadkach, zwiększenie liczby wątków nie zwiększa prędkości działania. Jakieś sugestie dlaczego?

Podaj cały aktualny kod.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 3x, ostatnio: Wibowit
0

Algorytm dalej jest niedeterministyczny

Dlaczego? Dodałem dwa sleepy a mimo to algorytm wydaje się działać dobrze. Co prawda nie sprawdziłem wszystkich liczb, ale dla ~340k liczb pierwsze 10k się zgadzało. Dodatkowo zgodnie z twierdzeniem o liczbach pierwszych ilość liczb w badanym przedziale też raczej mi się zgadzała. 324150 względem moich 348513.

Klasa główna

Kopiuj


import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ConcurrentTest {
    public static void main(String[] args) throws InterruptedException{
        Sieve task = new Sieve();
        int x = 5000000;
        int t = 4;
        task.setArray(x);
        Long beg = new Date().getTime();
        ExecutorService exec = Executors.newCachedThreadPool();
      for(int i = 0; i < t;i++){
            exec.execute(task);
        }
        exec.shutdown();
        Long time = 0L;
        while(true)
            if(exec.isTerminated()){
                time = new Date().getTime()-beg;
                break;
            }

        task.printArray();
        System.out.println("Time is "+time);
    }
}

Klasa Sieve

Kopiuj
import java.util.concurrent.ConcurrentHashMap;

public class Sieve implements Runnable {
	private ConcurrentHashMap<Integer, Boolean> array = new ConcurrentHashMap<Integer, Boolean>();
	private int x;
	private int counter = 2;
//	private AtomicInteger counter = new AtomicInteger(2);
//	 
//    public void run() {
//            List<Integer> list = new ArrayList<Integer>();        
//                    while (counter.get() < x) {
//                            list.add(counter.get());
//                            counter.incrementAndGet();
//                    //         try {
//                            // Thread.sleep(1);
//                            // } catch (InterruptedException e) {}
//                            // Thread.yield();
//            }
//            for (Integer it : list) {
//                      System.out.println(it.intValue());
//                    int n = it.intValue();
//                    if (array.get(n))
//                            continue;
//                    for (int i = 2 * n; i <= x; i += n) 
//                                    array.put(i, true);
//            }
//    }
	public void run() {

		int n = 0;
		while(true){
			sleep((int)Math.random()*500);
			n = getCounter();
			if( n == -1)
				break;
			if (array.get(n))
				continue;
			for (int i = 2 * n; i <= x; i += n) {
				sleep((int)Math.random()*500);
					array.put(i, true);
			}
		}
	}
	private synchronized int getCounter(){
		if( counter < x)
			return counter++;
		else return -1;
	}
	public void setArray(int x) {
		this.x = x;
		for (int i = 2; i <= x; i++)
			array.put(i, false);
	}

	public void printArray() {

		for (int i = 2; i <= array.size(); i++) {
			if (!array.get(i))
				System.out.println(i);

		}
	}
	private void sleep(int time){
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {}
	}
}

__krzysiek85
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 9 lat
  • Postów:1019
1

W tym rozwiązaniu możliwe jest, że wątki będą niepotrzebnie przetwarzać wielokrotności liczb pierwszych, np.

Wątek 1 pobiera liczbę 2 i traci procesor
Wątek 2 pobiera liczbę 3 i traci procesor
Wątek 3 pobiera liczbę 4, sprawdza, że 4 jeszcze nie jest odsiane (wątek 1. jeszcze nie zdążył tego zrobić) i zaczyna odsiewać wielokrotności 4.

Wątek 3. wykona niepotrzebną pracę, gdyż wątek 1. też odsiałby te liczby (wielokrotności 4 są też wielokrotnościami 2).


Registered Linux user #456405 | SCJP 6 | SCWCD 5 | SCBCD 5
edytowany 2x, ostatnio: __krzysiek85
KR
Na ogół wykonanie nieco niepotrzebnej pracy jest korzystniejsze niż oczekiwanie na blokadę. Zwłaszcza, że tu sytuacja, którą opisujesz jest bardzo mało prawdopodobna.
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:44 minuty
0

Ano tak, @__krzysiek85 ma rację. Algo w sumie jednak zadziała dobrze, tylko wykona trochę niepotrzebnej pracy. Kod trzeba sprofilować, może to zrobię niedługo.

Spróbuj zamienić ConcurrentHashMap na zwykłą tablicę booleanów.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
0

Na początku zakładałem, że nie będę tylko zmieniał flagi false na true, lecz będę faktycznie usuwał elementy z mapy. Fakt zmiany zmiany wartości true na false wyniknął po problemach z synchronizacją. Po zmianie mapy na tablicę booleanów problem braku przyspieszenia dalej nie został rozwiązany. Wróciłem więc do HashMapy i postanowiłem usuwać wartości co zmniejsza trochę liczbę iteracji. Dodatkowo przeprowadziłem kilka testów dla różnej liczby wątków.

Testy przy zmianie wartości na true.

Liczba wątków 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Test1 2271 2323 2265 2189 2162 2022 2074 2044 2039 1981 2140 1979 2131 2104 2098 2095 2031 1994 2066 1993
Test2 2443 2294 2215 2194 2204 2098 2052 1955 1985 2162 1949 2077 2145 2103 2068 1981 2124 2041 2131 2039
Test3 2448 2283 2225 2180 2164 2179 2109 2118 2085 2132 2037 2041 1998 1998 2141 1972 2097 2117 2100 2047

Testy przy usuwaniu/wykreślaniu

Liczba wątków 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Test1 2024 1908 2073 1869 1908 1924 1929 1901 1862 1926 1937 1874 1913 1973 1851 1923 1841 1810 2007 1835
Test2 1923 2015 1996 1926 1895 1972 1871 1923 1974 1924 1895 2770 1920 1877 1979 1992 1915 1975 1849 1795
Test3 1933 1900 1849 1936 1959 1882 1832 1890 1880 2307 1828 1848 1838 1856 1792 1862 1905 1892 1804 1870

Przy usuwaniu następuje nieznaczna poprawa szybkości, jednak problem z wątkami nadal występuje.

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:44 minuty
0

Twój procesor jest w stanie obsłużyć 20 wątków jednocześnie?


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
0

Nie, ale byłem ciekawy jakie będą wyniki. Spodziewałem się znacznego spowolnienia.

KR
Moderator
  • Rejestracja:prawie 21 lat
  • Ostatnio:dzień
  • Postów:2964
0

HashMapa do implementacji sita? To musi być okropnie powolne.
Takie rzeczy się robi na BitSetach. A jeszcze lepiej własna implementacja BitSet na AtomicIntegerArray, bez jakiejkolwiek synchronizacji, wtedy może wielowątkowa implementacja będzie mieć jakiś sens.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)