HPUNIX Сайт о ОС и не только!

Познакомился с языком программирования Go

8 февраля 2012 - unix
Познакомился с языком программирования Go

В сей заметке пойдет речь о языке Go, с которым я имел наслаждение познакомиться несколько недель вспять. Будут освещены особенности языка и разобрана маленькая программа на нем. В итоге я поделюсь своими личными впечатлениями от работы с Go.

Изучаем Go «за 20 четыре часа»

Если для вас охото ознакомиться с синтаксисом языка Go, безотступно рекомендую прочесть лаконичный пересказ Effective Go на российском языке. Отличительные черты языка:

  • Строгая статическая типизация (утиная типизация в случае интерфейсов);
  • Настоящая поддержка юникода;
  • Java/Python/Haskell-подобный собиратель мусора;
  • Остальные фишки многофункционального программирования — лямбды, замыкания и тп;
  • В Go есть указатели, но над ними нельзя делать арифметические операции, как в C/C++/D;
  • Так именуемые goroutines — легковесные потоки, для управления которыми и взаимодействия меж которыми в Go предусмотрены комфортные средства;
  • Отсутствие ООП-фанатизма, по сути Go является процедурным языком с поддержкой интерфейсов;
  • Нет поддержки исключений, заместо их предлагается использовать интерфейс error и возможность функций возвращать несколько значений;
  • Язык является интерпретируемым и компилируемым, при разработке Go повышенное внимание уделялось скорости компиляции;
  • Разработан в Гугл, проектированием занимались Кен Томпсон, Роб Пайк и Роберт Гризмер, если эти имена для вас о кое-чем молвят;

Go - среда с открытым исходным кодом, которая упрощает разработку простого, надежного и эффективного ПО.

Установка Go под Debian:

sudo apt-get install golang

Под FreeBSD существует бинарный пакет, но он достаточно старенькый. Устанавливаться из портов Go отказался, мол «go-1.0.1,1 is only for amd64, while you are running i386» 0_o. Но установка в согласовании с аннотацией на веб-сайте проекта прошла без заморочек.

Пуск интерпретатора:

go run test.go

Компиляция:

go build test.go

В качестве IDE я использовал собственный возлюбленный VIM. Подсветка синтаксиса настраивается так:

mkdir -p ~/.vim/syntax/
cd ~/.vim/syntax/
wget http://go.googlecode.com/hg-history/release/misc/vim/syntax/go.vim
mkdir -p ../ftdetect/
echo 'au BufRead,BufNewFile *.go set filetype=go' > ../ftdetect/go.vim

Вроде, все. Как там обстоят дела под Windows — не ведаю.

Сейчас напишем малость кода

Разглядим задачку из программерского конкурса от Drakus’а за июнь. Обычно, при исследовании нового языка программирования, поначалу я пишу прогу на уже знакомом мне языке, в роли которого обычно выступает Perl:

#!/usr/bin/perl

use strict;
use warnings;

# Stars task solver - Perl version
# (c) Alexandr A Alexeev | http://eax.me/

my %cubes;
my $min_dist = 999_999_999;
my @min_pair = (undef, undef);
my $infile = shift;

my $nbits = 9;

open my $fid, $infile or die $!;
my $nline = 0;
while(<$fid>) {
s/(^\s+|\s+$)//gs;
  my ($x,$y,$z) = split /\s+/;
  my @compare = ();
  my ($cx, $cy, $cz) = ( ($x >> $nbits),
                         ($y >> $nbits),
                         ($z >> $nbits) );
  for my $dx( (-1, 0, 1) ) {
    for my $dy( (-1, 0, 1) ) {
      for my $dz( (-1, 0, 1) ) {
        my $ncube = ($cx + $dx).'.'.($cy + $dy).'.'.($cz + $dz);
        next unless defined $cubes{$ncube};
        push @compare, $_ for(@{$cubes{$ncube}});
      }
    }
  }

  for my $curr(@compare) {
    my $dist = ($x - $curr->[0])**2 +
               ($y - $curr->[1])**2 +
               ($z - $curr->[2])**2;
    next unless $dist > 0;
    if($dist < $min_dist) {
      $min_dist = $dist;
      @min_pair = ([$x, $y, $z], $curr);

Конструкторы LEGO в учебной деятельности школьников

    }
  }

  push @{$cubes{$cx.'.'.$cy.'.'.$cz}}, [$x, $y, $z];

  $nline++;
  if($nline % 10 тыщ == 0) {
    warn "parsed $nline lines, min_dist**2 = $min_dist\n";
  }
}
close $fid;
print "DONE! MIN_DIST = ".sqrt($min_dist)."\n";
print "($min_pair[0][0],$min_pair[0][1],$min_pair[0][2])\n";
print "($min_pair[1][0],$min_pair[1][1],$min_pair[1][2])\n";

… а потом переписываю ее на изучаемый язык:

package main

/*
  Stars task solver - Go version
  (c) Alexandr A Alexeev | http://eax.me/
*/

import (
    "github.com/glenn-brown/golang-pkg-pcre/src/pkg/pcre"
    "container/list"
    "strconv"
    "bufio"
    "math"
    "fmt"
    "os"
  )

type Point3D struct {
  x,y,z int
}

const nbits = 9

func pointToKey(point Point3D) Point3D {
  return Point3D {
Познакомился с языком программирования Go
      point.x >> nbits,
      point.y >> nbits,
      point.z >> nbits,
    }
}

type PointReader pcre.Regexp

func newPointReader() (pr PointReader) {
  re := pcre.MustCompile("(\\d+)\\s+(\\d+)\\s+(\\d+)", 0)
  return PointReader(re)
}

func (pr PointReader) readPoint(str string) (
    rslt Point3D, err error) {
  m := pcre.Regexp(pr).MatcherString(str,0)
  if !m.Matches() {
    err = fmt.Errorf("Failed to parse '%v'\n", str)
    return
  }

  x, _ := strconv.Atoi(string(m.Group(1)))
  y, _ := strconv.Atoi(string(m.Group(2)))
  z, _ := strconv.Atoi(string(m.Group(3)))
  rslt = Point3D{x,y,z}
  return
}

func pow2(x int) int {
  return x * x;
}

func main() {
  if len(os.Args) < Два {
    fmt.Fprintf(os.Stderr, "Usage:\n%v [infile]\n", os.Args[0])
    return
  }

  fid, ferr := os.Open(os.Args[1])
  if ferr != nil {
    return
  }

  cubes := make(map[Point3D]*list.List);
  reader := bufio.NewReader(fid);
  minDist := 999999999
  minPair := make([]Point3D, 2)
  nline := 0;
  pr := newPointReader()
  for {
    line, rerr := reader.ReadString('\n')
    if rerr != nil { break }

    point, perr := pr.readPoint(line)
    if perr != nil {
      fid.Close()
      return
    }

    compare := list.New()
    initKey := pointToKey(point)
    for dx := -1; dx <= 1; dx++ {
      for dy := -1; dy <= 1; dy++ {
        for dz := -1; dz <= 1; dz++ {
          key := initKey
          key.x += dx
          key.y += dy
          key.z += dz
          values, exists := cubes[key]
          if !exists { continue }
          compare.PushBackList(values)
        }
      }
    }

    for curr := compare.Front();curr != nil;curr = curr.Next(){
      currPoint, _ := curr.Value.(Point3D)
      dist := pow2(point.x - currPoint.x) +
              pow2(point.y - currPoint.y) +
              pow2(point.z - currPoint.z)
      if dist == Нуль { continue }
Познакомился с языком программирования Go
      if dist < minDist {
        minPair[0] = point
        minPair[1] = currPoint
        minDist = dist
      }
    }

    value, exists := cubes[initKey]
    if !exists {
      value = list.New()
      cubes[initKey] = value
    }
    value.PushBack(point)

    nline++;
    if nline % 10 тыщ == Нуль {
      fmt.Printf("Parsed %v lines, minDist**2 = %v\n",
        nline, minDist)
    }
  }
  fid.Close()

  fmt.Printf("MIN_DIST = %v, minPair = %v\n",
    math.Sqrt(float64(minDist)), minPair);
}

Думается, в общих чертах текст данной программки должен быть ясен хоть какому более-менее опытнейшему программеру. Направьте внимание на то, как в Go происходит обработка ошибок, выделение памяти, преобразование типов и проверка на существование элемента в ассоциативном массиве с данным ключом.

Но тут применены далековато не все особенности Go. Как минимум, за кадром остались интерфейсы, goroutines и лямбды, но эти и другие вопросы я обязан бросить для вас для самостоятельного исследования.

Вы, конечно, не могли не направить внимание на внедрение в данной программке библиотеки PCRE. Очевидно, программка во время собственной работы ничего не закачивает с гитхаба, просто таким макаром в Go разрешаются конфликты в именах библиотек. Установка упомянутой библиотеки под Debian делается последующим образом:

sudo apt-get install libpcre++-dev
sudo go get github.com/glenn-brown/golang-pkg-pcre/src/pkg/pcre

Я был обязан использовать PCRE, так как стандартная библиотека Go для работы с постоянными выражениями на сто процентов написана на самом Go. В связи с этим, ее производительность не то, чтоб ни на что не годилась, но все таки приметно уступает PCRE.

Мой 1-ый вариант программки на Go решал намеченную цель за Двести 20 5 секунд, используя Триста пятнадцать Мб оперативки, при этом Perl-скрипту требовалось всего только 100 секунд и на каких-либо 50 Мб больше оперативки. Сначала я был очень расстроен.

Но разобравшись в дилемме и произведя надлежащие оптимизации (внедрение PCRE, кэширование скомпилированных постоянных выражений и некие другие), я сотворил программку, которую привел выше. На моем средненьком, по сегодняшним меркам, компьютере она совладевает с задачей за 20 восемь секунд и употребляет 100 70 семь Мб оперативки.

Есть и другие свидетельства (один и два) очевидного приемущества Go в плане производительности не только лишь над интерпретируемыми, да и некими компилируемыми языками программирования:

Бенчмарк с участием Google Go

Что типично, во время работы программки происходит несколько очень маленьких, но все таки приметных невооруженным взором подвисаний. Вероятнее всего, во время этих подвисаний запускается собиратель мусора, который перекрывает выполнение всех потоков. В компании Мозилла отсутствие такого эффекта именуют основным преимуществом собственного языка программирования Rust перед Go.

Мой вердикт следующий…

После долголетнего опыта работы с Perl, язык Go кажется мне очень многоречивым. Сравните приведенные выше исходники либо попытайтесь написать на Go аналог последующего кода:

  print "$_ => $hash{$_}\n"
    for sort { $hash{$a} <=> $hash{$b} } keys %hash;

Но во всем остальном он очень даже хорош. Естественно, он не так крут, как православный язык Haskell, но на фоне всех других узнаваемых мне языков смотрится вправду здорово.

Go прост в исследовании и имеет широкую область внедрения. Язык представляет собой хороший компромисс меж удобством/выразительностью скриптовых и строгостью/производительностью компилируемых языков. Хотя баланс чуток посильнее смещен в сторону Си, ежели я ждал.

Сейчас уже был выпущен Go 1.0, в каком совсем зафиксировали синтаксис языка. На веб-сайте проекта можно отыскать много пригодной документации и огромную коллекцию готовых библиотек (см также этот перечень). В Гугл Groups было найдено активное общество программистов.

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

А вы уже пробовали писать на Go? Если да, то каковы ваши воспоминания от этого языка? Если нет, то планируете ли испытать?

Похожие статьи

Теги:
Рейтинг: 0 Голосов: 177 955 просмотров
Комментарии (0)

Нет комментариев. Ваш будет первым!

Найти на сайте: параметры поиска

Windows 7

Среда Windows 7 на первых порах кажется весьма непривычной для многих.

Windows 8

Если резюмировать все выступления Microsoft на конференции Build 2013.

Windows XP

Если Windows не может корректно завершить работу, в большинстве случаев это

Windows Vista

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