Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2013.07.28;
Скачать: [xml.tar.bz2];

Вниз

Ребят, потестите пожалуйста   Найти похожие ветки 

 
DevilDevil ©   (2013-02-13 10:25) [0]

Разрабатываю библиотеку для скоростного буферезированного чтения/записи файлов. Осенила меня идея, что можно добавить в такой алгоритм "чтение/запись куска памяти в файле в отдельном потоке", дабы не тормозить hardware работой основной поток.

Написал бенчмарк для записи файла (около 100мб) стандартными подходами и с помощью моей библиотеки. Результаты работы (моей библиотеки) меня удивляют. Но для более общей картины хочу попросить вас протестировать бенчмарк на нескольких машинах.

Вот ссылка: http://zalil.ru/34256579
Бенчмарк выполняется около часа. За счёт вариантов записи в TFileStream и в TMemoryStream. Так что уходя на обед вполне можно запустить. Но если не хотите ждать или нет времени - можете в исходнике закомментировать строки:
 RunBenchmarkProc("Standard TFileStream writer", StreamWriter, false);
 RunBenchmarkProc("Standard TMemoryStream+SaveToFile()", StreamWriter, true);


Спасибо за помощь


 
Владислав ©   (2013-02-13 11:38) [1]

А зачем это все?
Не проще создать буфер, наполнять его, а по наполнении использовать тот же TFileStream?
А бенчмарк некорректный, если Вы пытаетесь сравнить свой способ с записью через TFileStream. Для корректного сравнения в случае TFileStream нужно сначала наполнять буфер такого же размера, а потом использовать TFileStream для записи в файл.


 
DevilDevil ©   (2013-02-13 12:25) [2]

> А зачем это все?

для того чтобы сравнить различные способы записи в файл
можете добавить свой метод

по поводу некорректности
во-первых, запись в файл в ОС тоже должна быть умная и эффективно кэшировать данные. Ну да фиг с ним
во-вторых, мой метод принципиально не отличается от "наполнять буфер такого же размера, а потом использовать TFileStream для записи в файл". Отличие состоит в заранее выбранном размере буфера, выравнивании памяти, пара дополнительных фишек, возможно производить запись в другом потоке. Как я уже сказал, можете добавить бенчмарк другого подхода - будет интересно

На данный момент меня больше интересует не TFileStream и не TMemoryStream. Меня интересуют различные вариации записи через мой "класс"


 
Владислав ©   (2013-02-13 12:42) [3]


> для того чтобы сравнить различные способы записи в файл

Способ в итоге один: WriteFile.


> можете добавить свой метод

Чтобы добавить метод, нужно знать цель. Если просто "посравнивать", то Вы эту цель уже выполнили. :)


> можете добавить бенчмарк другого подхода - будет интересно

Все эти бенчмарки зависят от задачи.


> Меня интересуют различные вариации записи через мой "класс"

Мне не очень понятно, для чего нужны Ваши классы. Последовательное чтение и последовательная запись в файл?


 
DevilDevil ©   (2013-02-13 12:47) [4]

> Владислав ©   (13.02.13 12:42) [3]

когда стоит задача обработки большого объёма данных (ну минимум 100мб), и эти данные хранятся в файлах - возникает много рутинной работы. Я решил написать одно высокоэффективное решение.

опять таки в бенчмарке показано, что частоиспользуемые TFileStream и TMemoryStream в таких плохо подходят. Приходится писать свой код для буферезированного чтения/записи. Моя библиотека этим и занимается. Только задача библиотеки в частности выжать максимум производительности.

приведите цифры бенчмарка пожалуйста


 
O'ShinW ©   (2013-02-13 12:49) [5]

ничего не смотрел, просто запустил
Win7 64бит SP1
Intel(R) Core(TM) i3-2120 CPU @ 3.30GHz
4 гига RAM
IDE\DiskWDC_WD5000AAKX-001CA0

The benchmark shows how quickly you can write files
Destination file must be same as "correct_file.txt" (about 100Mb)
Test data generating... done.

Let"s test methods (it may take an hour, but try to wait):
1.txt - "Standard TFileStream writer"... 73601ms
comparing with correct file... binary equal.
2.txt - "Standard TMemoryStream+SaveToFile()"... 294842ms
comparing with correct file... binary equal.
3.txt - "Simple CachedFileWriter"... 2293ms
comparing with correct file... binary equal.
4.txt - "Simple CachedFileWriter+DoubleThreading"... 2496ms
comparing with correct file... binary equal.
5.txt - "Fast CachedFileWriter"... 141ms
comparing with correct file... binary equal.
6.txt - "Fast CachedFileWriter+DoubleThreading"... 109ms
comparing with correct file... binary equal.

Press Enter to quit



 
Владислав ©   (2013-02-13 12:56) [6]


The benchmark shows how quickly you can write files
Destination file must be same as "correct_file.txt" (about 100Mb)
Test data generating... done.

Let"s test methods (it may take an hour, but try to wait):
1.txt - "Simple CachedFileWriter"... 312ms
comparing with correct file... binary equal.
2.txt - "Simple CachedFileWriter+DoubleThreading"... 265ms
comparing with correct file... binary equal.
3.txt - "Fast CachedFileWriter"... 218ms
comparing with correct file... binary equal.
4.txt - "Fast CachedFileWriter+DoubleThreading"... 187ms
comparing with correct file... binary equal.

Press Enter to quit


Если Вам нужно последовательное чтение и последовательная запись в файл на OS Widows, смотрите в сторону CreateFile + FILE_FLAG_NO_BUFFERING + FILE_FLAG_SEQUENTIAL_SCAN + FILE_FLAG_WRITE_THROUGH (в правильном сочетании флагов).


 
DevilDevil ©   (2013-02-13 12:59) [7]

> O"ShinW ©   (13.02.13 12:49) [5]
> Владислав ©   (13.02.13 12:56) [6]

спасибо.

> Если Вам нужно последовательное чтение и последовательная
> запись в файл на OS Widows, смотрите в сторону


а можно поподробнее об этих флагах ?
может у себя на машине поэкспериментируете в TCachedFileWriter ?


 
Владислав ©   (2013-02-13 13:09) [8]

The benchmark shows how quickly you can write files
Destination file must be same as "correct_file.txt" (about 100Mb)
Test data generating... done.

Let"s test methods (it may take an hour, but try to wait):
1.txt - "Standard TFileStream writer"... 198106ms
comparing with correct file... binary equal.
2.txt - "Standard TMemoryStream+SaveToFile()"... 1357ms
comparing with correct file... binary equal.
3.txt - "Simple CachedFileWriter"... 281ms
comparing with correct file... binary equal.
4.txt - "Simple CachedFileWriter+DoubleThreading"... 265ms
comparing with correct file... binary equal.
5.txt - "Fast CachedFileWriter"... 203ms
comparing with correct file... binary equal.
6.txt - "Fast CachedFileWriter+DoubleThreading"... 171ms
comparing with correct file... binary equal.

Press Enter to quit



> а можно поподробнее об этих флагах ?

В справке по функции CreateFile.


> может у себя на машине поэкспериментируете в TCachedFileWriter
> ?

Нет на это времени. :)


 
Slym ©   (2013-02-13 13:36) [9]

Лихо ты с несозданными экземплярами орудуешь...
var Writer: TCachedFileWriter;
begin
 Writer.Initialize(FileName, Flag);


 
Владислав ©   (2013-02-13 13:43) [10]


> Лихо ты с несозданными экземплярами орудуешь...


Since object types do not descend from Borland.Delphi.System.TObject, they provide no built-in constructors, destructors, or other methods. You can create instances of an object type using the New procedure and destroy them with the Dispose procedure, or you can simply declare variables of an object type, just as you would with records.


 
DevilDevil ©   (2013-02-13 14:18) [11]

> Нет на это времени. :)

ога )))))


 
Дмитрий С ©   (2013-02-13 14:30) [12]

100Mb за 171мс, это 580 мегабайт в секунду. Это что за жесткий такой?


 
Владислав ©   (2013-02-13 14:37) [13]


> Дмитрий С ©   (13.02.13 14:30) [12]

HDD. А время не мое, не разбирался, что оно означает.


 
DevilDevil ©   (2013-02-13 15:30) [14]

Убрал запись через TFileStream и TMemoryStream
добавил бенчмарк на чтение
http://zalil.ru/34257617

протестируйте пожалуйста
можно запустить файл "benchmarks.bat" - он выдаст файл "benchmarks.log"


 
Дмитрий С ©   (2013-02-13 15:35) [15]


> DevilDevil ©   (13.02.13 15:30) [14]

Твой класс позволяет записать 580 мегабайт в секунду?


 
Дмитрий С ©   (2013-02-13 15:37) [16]


> 2.txt - "Standard TMemoryStream+SaveToFile()"... 294842ms
> comparing with correct file... binary equal.


> 1.txt - "Standard TFileStream writer"... 198106ms
> comparing with correct file... binary equal.

Вообще во все это верится слабо.
Почему так доооолго?


 
dmk ©   (2013-02-13 15:52) [17]

win7 64 - ST31500341AS

Let"s test methods (it may take an hour, but try to wait):
1.txt - "Standard TFileStream writer"... 52525ms
comparing with correct file... binary equal.
2.txt - "Standard TMemoryStream+SaveToFile()"... 252051ms
comparing with correct file... binary equal.
3.txt - "Simple CachedFileWriter"... 1170ms
comparing with correct file... binary equal.
4.txt - "Simple CachedFileWriter+DoubleThreading"... 1139ms
comparing with correct file... binary equal.
5.txt - "Fast CachedFileWriter"... 140ms
comparing with correct file... binary equal.
6.txt - "Fast CachedFileWriter+DoubleThreading"... 94ms
comparing with correct file... binary equal.

>binary equal
У меня обычным BlockWrite (в цикле) 538 Мб за 381 мс записалось (писалка TIFF"ов написанная 9 лет назад :)
100 Мб пишет за 79 мс vs ваши 94 мс. IMHO лучше оставить эту задачу на совести ОС.


 
DVM ©   (2013-02-13 16:02) [18]


> У меня обычным BlockWrite (в цикле) 538 Мб за 381 мс записалось
> (писалка TIFF"ов написанная 9 лет назад :)

куда оно с такой скоростью записалось да еще 9 лет назад?


 
Дмитрий С ©   (2013-02-13 16:07) [19]


> куда оно с такой скоростью записалось да еще 9 лет назад?

Видимо в кеш записи:)


 
dmk ©   (2013-02-13 16:13) [20]

DVM ©   (13.02.13 16:02) [18]
В кэш скорее всего. А записалось сегодня. С тех пор 4 компьютера сменил.


 
DevilDevil ©   (2013-02-13 16:19) [21]

> Дмитрий С ©
> Твой класс позволяет записать 580 мегабайт в секунду?

ну современные винчестеры позволяют писать ещё с большей скоростью

> Вообще во все это верится слабо.
> Почему так доооолго?


TMemoryStream долго потому, что постоянно перевыделяет память. Если не ошибаюсь - по 8кб. А тут их надо 100Мб

TFileStream тормозит потому, что происходит очень много обращений к файловой системе

> dmk ©   (13.02.13 15:52) [17]
> IMHO лучше оставить эту задачу на совести ОС.

по сути без DoubleThreading - и есть "на совести ОС"

Спасибо за тест!
посмотри ещё reader пожалуйста ! (последняя ссылка)


 
Дмитрий С ©   (2013-02-13 16:26) [22]


> TMemoryStream долго потому, что постоянно перевыделяет память.
>  Если не ошибаюсь - по 8кб. А тут их надо 100Мб
>
> TFileStream тормозит потому, что происходит очень много
> обращений к файловой системе

Так это идиотизм писать по 8кб такой объем. Так никто не будет делать.


 
DevilDevil ©   (2013-02-13 16:31) [23]

> Дмитрий С ©   (13.02.13 16:26) [22]
> Так это идиотизм писать по 8кб такой объем. Так никто не
> будет делать.


пока я тебе не сказал - ты не знал этого факта о TMemoryStream
следовательно на практике тебя мало что может остановить от использования TMemoryStream

это я к чему
люди вообще слабо заботятся об оптимизациях. Особенно если не знают внутренних механизмов: классов, RTTI, ассемблера

отчасти поэтому я пишу такие "классы". Чтобы разочек написать, отладить, и больше не возвращаться


 
Дмитрий С ©   (2013-02-13 16:34) [24]


> пока я тебе не сказал - ты не знал этого факта о TMemoryStream
> следовательно на практике тебя мало что может остановить
> от использования TMemoryStream

в него тоже можно по разному писать, например сразу
MS.Size := 100*MB;
Как и в файл, чтобы не мучить файловую систему.

Интересно а как твой класс выбирает приращение блоков памяти?


 
DVM ©   (2013-02-13 16:39) [25]


> DevilDevil ©   (13.02.13 16:19) [21]
> > Дмитрий С ©
> > Твой класс позволяет записать 580 мегабайт в секунду?
>
> ну современные винчестеры позволяют писать ещё с большей
> скоростью

Ну это сказки. Пропускная способность даже для SAS - 3000 мбит/сек и это в теории, на практике меньше, а это равно 375 МБАЙТ/СЕК

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

 Stream := TBufferedStream.Create(TFileStream.Create("test.dat", fmCreate or fmOpenWrite), 65534, true);

Получилось 1500 мсек.


 
DevilDevil ©   (2013-02-13 16:42) [26]

> Дмитрий С ©   (13.02.13 16:34) [24]

> Интересно а как твой класс выбирает приращение блоков памяти?

не поверишь
для любого файла используется 256кб памяти

> в него тоже можно по разному писать, например сразу
> MS.Size := 100*MB;


можно конечно
к примеру не так давно я использовал свой аналог TMemoryStream (TFastMemoryWriter) который динамически выбирает коэффициент приращения. Т.е. чем больше данных записано - тем больше коэффициент приращения. Если выберешь константный размер (как например в TMemoryStream) то можешь не угадать с размером. Может писаться слишком медленно или напротив захаваться слишком много памяти для малых задач. В целом для потоковой записи или чтения (особенно файлов и особенно больших) - лучше использовать "классы" типа моих


 
DevilDevil ©   (2013-02-13 16:45) [27]

> DVM ©   (13.02.13 16:39) [25]

> Ну это сказки.

буду знать

> Я кстати попробовал сделать тест для записи строк в файл
> аналогичный твоему


да, да !
мы говорили с тобой о твоём классе

> Получилось 1500 мсек.

это круто конечно :)
но сколько выдаёт мой "класс" :)
ты засунь свой TBufferedStream в бенчмарк. Сделай по аналогии с TStream


 
Jeer ©   (2013-02-13 16:49) [28]

Хрень какая-то:
1. Бенч на HDD
2. Бенч на RAM

http://s16.radikal.ru/i191/1302/f4/928cd4f71c03.png


 
DVM ©   (2013-02-13 16:52) [29]


> DevilDevil ©   (13.02.13 16:45) [27]


> ты засунь свой TBufferedStream в бенчмарк.

у меня твой код не компилируется в XE2 там исправлять надо в нескольких местах.


 
DevilDevil ©   (2013-02-13 16:53) [30]

> Jeer ©   (13.02.13 16:49) [28]

эммм.. я может что-то не понимаю
что значит "на RAM" ?

кстати запусти лучше "benchmarks.bat" отсюда: http://zalil.ru/34257617
он выдаст файл "benchmarks.log"
здесь убран TFileStream и TMemoryStream, добавлен бенч на чтение


 
DVM ©   (2013-02-13 16:55) [31]


> DevilDevil ©   (13.02.13 16:45) [27]


> но сколько выдаёт мой "класс" :)

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


 
DevilDevil ©   (2013-02-13 16:57) [32]

> у меня твой код не компилируется в XE2 там исправлять надо
> в нескольких местах.


кстати я планирую отдать библиотеку общественности (когда разберусь с DoubleThreading и т.д.). Чтобы потом была поддержка всех Delphi, в том числе FPC, x64, ARM, Linux, MacOS, iOS

странно что не компилируется
исправь если можешь
и скажи в чём была проблема - на будущее


 
DVM ©   (2013-02-13 17:00) [33]


> DevilDevil ©   (13.02.13 16:57) [32]


> и скажи в чём была проблема - на будущее

Например тут:

function FuncThreadFinalizing(Parameter: pointer): integer;
begin
 with (PCachedBufferThreadMemory(Parameter)^) do
 begin
   if (State = STATE_DONE) then State := STATE_FINALIZE;   // <===тут
   Result := State;
 end;
end;


[DCC Error] CachedBuffers.pas(533): E2064 Left side cannot be assigned to


 
Дмитрий С ©   (2013-02-13 17:00) [34]


> DevilDevil ©   (13.02.13 16:57) [32]

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


 
Jeer ©   (2013-02-13 17:04) [35]

Win7 64 Intel 16Gb

Ну вот тебе на HDD SCSI:

------- writing_benchmark.exe -------
The benchmark shows how quickly you can write files
Destination file must be same as "correct_file.txt" (about 100Mb)
Test data generating... done.

Let"s test methods:
1.txt - "Simple CachedFileWriter"... 1467ms
comparing with correct file... binary equal.
2.txt - "Simple CachedFileWriter+DoubleThreading"... 7753ms
comparing with correct file... binary equal.
3.txt - "Fast CachedFileWriter"... 140ms
comparing with correct file... binary equal.
4.txt - "Fast CachedFileWriter+DoubleThreading"... 7613ms
comparing with correct file... binary equal.
.
.
.
------- reading_benchmark.exe -------
The benchmark shows how quickly you can read/parse files
Testing file is "correct_file.txt" (about 100Mb)
Total sum of numbers must be equal 0x2904E86C0

Let"s test methods (it may take a few minutes):
1) "Standard TStringList reader"... 4696ms
2) "Fast buffering reader"... 483ms
3) "Using CachedFileReader"... 390ms
4) "Using CachedFileReader+DoubleThreading"... 375ms

И диск 2 Gb реализованный в памяти ( RAM )
------- writing_benchmark.exe -------
The benchmark shows how quickly you can write files
Destination file must be same as "correct_file.txt" (about 100Mb)
Test data generating... done.

Let"s test methods:
1.txt - "Simple CachedFileWriter"... 1466ms
comparing with correct file... binary equal.
2.txt - "Simple CachedFileWriter+DoubleThreading"... 7878ms
comparing with correct file... binary equal.
3.txt - "Fast CachedFileWriter"... 171ms
comparing with correct file... binary equal.
4.txt - "Fast CachedFileWriter+DoubleThreading"... 7379ms
comparing with correct file... binary equal.
.
.
.
------- reading_benchmark.exe -------
The benchmark shows how quickly you can read/parse files
Testing file is "correct_file.txt" (about 100Mb)
Total sum of numbers must be equal 0x2904E86C0

Let"s test methods (it may take a few minutes):
1) "Standard TStringList reader"... 4665ms
2) "Fast buffering reader"... 483ms
3) "Using CachedFileReader"... 375ms
4) "Using CachedFileReader+DoubleThreading"... 374ms


 
DevilDevil ©   (2013-02-13 17:05) [36]

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


так задача моих TCachedBufferWriter и TCachedBufferReader - такая же как у твоего TBufferedStream. Только:
1) принципиально различаются чтение и запись. У тебя насколько понял всё в одном
2) для файлов существуют отдельные "классы". Специально заточенные, чтобы больше не париться
3) у тебя насколько понял есть только Read() и Write(). Тут кроме "высокоуровневых" методов есть возможность работать с низким уровнем: Current, Margin(остаток в буфере) и Flush. Это позволяет снизить оверхед на вызов лишних методов. Типа Move/CopyMemory если пишем маленький объект константного размера. Используется object, а не class опять таки не случайно. Доступ к полям object быстрее доступа к полям class; особенно если object хранится на стеке. Кроме того такое использование положительно сказывается на кэш-френдли
4) выравнивание буферизированной памяти по границе в 4кб + дополнительные буферизированые зоны (Previous и Additional), которые иногда нужны.


 
DevilDevil ©   (2013-02-13 17:09) [37]

> Дмитрий С ©   (13.02.13 17:00) [34]

> добавь в бенч еще FlushFileBuffers перед закрытием и учитывай
> этот вызов во времени.


я в этом не разбираюсь
подкорректируй сам и вышли мне
или здесь положи

> DVM ©   (13.02.13 17:00) [33]

я чёт не понял. а в чём там ошибка то ?

> Jeer ©   (13.02.13 17:04) [35]

Спасибо!

P.S.
сдаётся мне либо не нужно использовать DoubleThreading, либо я его как-то неправильно реализую.


 
dmk ©   (2013-02-13 17:13) [38]

Читалка на SSD Intel-X25
1) "Standard TStringList reader"... 4165ms
2) "Fast buffering reader"... 468ms
3) "Using CachedFileReader"... 375ms
4) "Using CachedFileReader+DoubleThreading"... 374ms

Читалка на HDD ST31500341AS
1) "Standard TStringList reader"... 4165ms
2) "Fast buffering reader"... 453ms
3) "Using CachedFileReader"... 374ms
4) "Using CachedFileReader+DoubleThreading"... 375ms

Писалка на SSD Intel-X25
1.txt - "Simple CachedFileWriter"... 1186ms
comparing with correct file... binary equal.
2.txt - "Simple CachedFileWriter+DoubleThreading"... 1139ms
comparing with correct file... binary equal.
3.txt - "Fast CachedFileWriter"... 125ms
comparing with correct file... binary equal.
4.txt - "Fast CachedFileWriter+DoubleThreading"... 437ms
comparing with correct file... binary equal.

Писалка на HDD ST31500341AS
1.txt - "Simple CachedFileWriter"... 1185ms
comparing with correct file... binary equal.
2.txt - "Simple CachedFileWriter+DoubleThreading"... 1154ms
comparing with correct file... binary equal.
3.txt - "Fast CachedFileWriter"... 125ms
comparing with correct file... binary equal.
4.txt - "Fast CachedFileWriter+DoubleThreading"... 437ms
comparing with correct file... binary equal.

А если не видно разницы, зачем платить больше? :)
На самом деле SSD раза в 2 быстрее HDD в моем варианте.


 
dmk ©   (2013-02-13 17:15) [39]

Может попробовать разные данные писать и имена фалов разные, а то система может думать, что это одно и то же и кэширует.


 
DVM ©   (2013-02-13 17:19) [40]


> 1) принципиально различаются чтение и запись. У тебя насколько
> понял всё в одном

Да, в одном классе, разумеется


> 2) для файлов существуют отдельные "классы". Специально
> заточенные, чтобы больше не париться

У меня вообще нет привязки к источнику/приемнику данных, это декоратор.


> 3) у тебя насколько понял есть только Read() и Write().

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


> особенно если object хранится на стеке.

где то читал, что все уже в куче хранится.



Страницы: 1 2 3 4 5 вся ветка

Форум: "Прочее";
Текущий архив: 2013.07.28;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.006 c
15-1362571492
Pit
2013-03-06 16:04
2013.07.28
Раскрутка стека в Eureka log


2-1353496539
Xmen
2012-11-21 15:15
2013.07.28
Работа с потоком как организовать?


11-1247619060
Osmiy
2009-07-15 04:51
2013.07.28
Не отрисовывается Bitmap в ToolBar


15-1362398967
Kerk
2013-03-04 16:09
2013.07.28
Обход графа


2-1354043911
adept
2012-11-27 23:18
2013.07.28
Операции с данными в ячейках StringGrid а





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский