Ответы пользователя по тегу Go
  • Где допустил ошибку при работе Golang pgx с postgresql?

    @falconandy
    Сначала залоггируйте full_text, возможно он приходит пустой и pgx ни при чем.
    full_text := r.FormValue("full_text")
    log.Print(full_text)


    Не работал с pgx, но обычно для Insert используют Exec вместо Query, хотя возможно нет никакой разницы.
    Ответ написан
  • Как считывать из бесконечного Stdout?

    @falconandy
    1. Т.к. питоновский скрипт работает вечно, я думаю, вам надо в отдельной горутине выдавать прочитанные строки в канал.
    2. Вы забыли запустить сам питоновский скрипт.
    3. Питон по умолчанию буферизирует вывод, можно добавить флаг -u для отключения буферизации.

    Что-то типа:
    package main
    
    import (
    	"bufio"
    	"os/exec"
    )
    
    func main() {
    	lines := read()
    	for line := range lines {
    		print(line)
    	}
    }
    
    func read() <-chan string {
    	lines := make(chan string)
    
    	go func() {
    		defer close(lines)
    
    		child := exec.Command("python", "-u", "./test.py")
    
    		stdout, err := child.StdoutPipe()
    		if err != nil {
    			return
    		}
    
    		err = child.Start()
    		if err != nil {
    			return
    		}
    		println("Started")
    
    		reader := bufio.NewReader(stdout)
    
    		for {
    			line, err := reader.ReadString('\n')
    			if err != nil {
    				break
    			}
    
    			lines <- line
    		}
    
    		err = child.Wait()
    		if err != nil {
    			println(err)
    		}
    	}()
    
    	return lines
    }
    Ответ написан
  • Почему не видно лог?

    @falconandy
    1. Канал quit не нужен - можно заменить на выход из цикла:
    Loop:
    	for {
    		...
    			if count == 10 {
    				break Loop
    			}
    		...
    	}
    
    	log.Println("quit")


    2. Тикер первый раз сработает не сразу, а только через 60 секунд (а main спит только 10 секунд). Надо разобраться с задержками, чтобы они соответствовали друг другу, или в main ждать не за счет sleep, а более явно (WaitGroup возможно).
    Ответ написан
    Комментировать
  • Что не так с потоками?

    @falconandy
    С "потоками" всё так, просто вы неправильно работаете с "массивом".

    perftracing = append(perftracing, 0) при исчерпании выделенной памяти выделяет новый блок памяти (по-моему удвоенного размера) и копирует текущие элементы в новый блок. Соответственно часть (половина) горутин пишет по старым адресам, а в выхлопе данные из последнего выделенного блока памяти.

    ...
    0 0 0 0 5197273 5671085 5177800 5797080 
    0 0 0 0 5197332 5671147 5177908 5797137 
    0 0 0 0 5197388 5671208 5178008 5797195 
    0 0 0 0 5197450 5671269 5178118 5797248
    ...


    Если создать "массив" заранее со всеми элементами, то всё выводится нормально:
    threads := 4
    perftracing := make([]int64, threads)
    for i := 0; i < threads; i++ {
    	go thread(&perftracing[i])
    	time.Sleep(1)
    }


    ...
    5593758 7107822 5575001 6449763 6321574 5535152 5728000 7196092 
    5593813 7107884 5575056 6449859 6321628 5535209 5728060 7196153 
    5593879 7107959 5575122 6449976 6321695 5535275 5728122 7196217 
    5593936 7108030 5575180 6450079 6321757 5535339 5728190 7196285 
    ...
    5594008 7108109 5575251 6450199 6321821 5535403 5728251 7196349


    Ну и вместо time.Sleep(1) вы наверно имели в виду что-то типа time.Sleep(time.Second * 1)

    Go 1.19.3, Kubuntu 22.04
    Ответ написан
    Комментировать
  • Как в Golang проверить вхождение строки в строку, но слово целиком?

    @falconandy
    Проще регуляркой, но не факт, что быстрее и покрывает все кейсы:
    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	text := "something, something1, othersomething"
    
    	fmt.Println("some", createWordRegex("some").MatchString(text))
    	fmt.Println("thing", createWordRegex("thing").MatchString(text))
    	fmt.Println("something", createWordRegex("something").MatchString(text))
    	fmt.Println("something1", createWordRegex("something1").MatchString(text))
    }
    
    func createWordRegex(word string) *regexp.Regexp {
    	return regexp.MustCompile(`\b` + regexp.QuoteMeta(word) + `\b`)
    }
    Ответ написан
    2 комментария
  • Почему проходит тест с моком при любом возвращаемом значении?

    @falconandy
    Есть тест, который тестирует умножение 5 на 5 и я хочу проверить что возвращается именно 25


    Если вы хотите протестировать логику метода
    func (m multiplier) Calculate(num int, times int) int
    , то мок вам не нужен - тестируйте этот метод без всяких моков.

    Если же вы хотите протестировать логику функции func CalculateFiveTimesFive(m Multiplier) int, то должны проверить в тесте, что она возвращает. При этом мок не обязан возвращать именно 25, а может вернуть любое число. По сути вы проверяете, что функция CalculateFiveTimesFive всегда возвращает результат вызова метода Calculate - такой тест выглядит довольно бесполезным (как и сама функция CalculateFiveTimesFive).

    m.On("Calculate", 5, 5).Return(37)
    assert.Equal(t, 37, multiplier.CalculateFiveTimesFive(m))
    m.AssertExpectations(t)
    Ответ написан
    Комментировать
  • Golang Stepik 3.9 Параллелизм ч.2 как решить?

    @falconandy
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	arguments := make(chan int)
    	done := make(chan struct{})
    	result := calculator(arguments, done)
    	for i := 0; i < 10; i++ {
    		arguments <- 1
    	}
    	close(done)
    	fmt.Println(<-result)
    }
    
    func calculator(arguments <-chan int, done <-chan struct{}) <-chan int {
    	output := make(chan int)
    
    	go func(output chan int) {
    		defer close(output)
    
    		var x int
    	Loop:
    		for {
    			select { // Оператор select
    			case arg, ok := <-arguments: // Ждет, когда проснется гофер
    				if !ok {
    					break Loop
    				}
    				x += arg
    				fmt.Println(x)
    			case <-done: // Ждет окончания времени
    				break Loop
    			}
    		}
    		output <- x
    	}(output)
    
    	return output
    }
    Ответ написан
  • Как подавить предупреждения от С библиотеки в Golang?

    @falconandy
    Нагуглил https://github.com/zimmski/osutil/blob/master/capt..., не проверял - может быть подойдет как идея реализации.
    Ответ написан
    Комментировать
  • Почему при чтении из канала с циклом появляется задержка в начале работы?

    @falconandy
    1. появляется задержка в начале работы - не понял, что за задержка. Поясните по возможности
    2. status_Ch := <-myChan для закрытого канала будет возвращать zero-значание (в данном случае 0) и цикл никогда не завершится. Проще всего переделать на for status_Ch := range myChan
    3.
    var testStatus = 200 // Тест-статус результата (меняется непредсказуемо с каждой итерацией цикла): 100 - успешно; 200 - неудачно.
    - вроде testStatus нигде не меняется
    Ответ написан
    3 комментария
  • Как правильно установить несколько версий го на одной системе?

    @falconandy
    Есть простой официальный способ, если он вам подходит. Бинарники будут называться типа go1.10.7
    Ответ написан
    Комментировать
  • Как узнать когда горутины закончили запись, чтобы закрыть канал?

    @falconandy
    Примерно так: https://goplay.tools/snippet/TciyGAE8dyn
    Ответ написан
    Комментировать
  • Как сделать вывод массива со сдвигом?

    @falconandy
    1. Строка text = '' * maximum + text выглядит бесполезной - для чего пустую строку пытаться реплицировать?
    2. Выхлоп вашего скрипта (на Python 3, но это не должно вроде влиять) отличается от вами приведенного. Не хватает укорачивания строк:
    ...
    wxxyyzz0011223344556677889900
    xxyyzz0011223344556677889900
    xyyzz0011223344556677889900
    yyzz0011223344556677889900
    yzz0011223344556677889900
    zz0011223344556677889900
    z0011223344556677889900
    0011223344556677889900
    011223344556677889900
    11223344556677889900
    1223344556677889900
    223344556677889900
    23344556677889900
    3344556677889900
    344556677889900
    44556677889900
    4556677889900
    556677889900
    56677889900
    6677889900
    677889900
    77889900
    7889900
    889900
    89900
    9900
    900
    00
    0

    3. Для текущей версии аналог на Go:
    package main
    
    func main() {
    	text := "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz0011223344556677889900"
    	show(text, 30)
    }
    
    func show(text string, maximum int) {
    	for i := range text {
    		if i+maximum < len(text) {
    			println(text[i : i+maximum])
    		} else {
    			println(text[i:])
    		}
    	}
    }
    Ответ написан
    1 комментарий
  • Проблема с range. Как решить?

    @falconandy
    Поменяйте имена полей структуры - начните их с заглавной буквы, чтобы сделать публичными (например, Name string).
    Ответ написан
    Комментировать
  • Не будет гонки и повреждения данных в памяти?

    @falconandy
    По-моему вы переусложняете без необходимости. Если значения из конфига только читаются, то потокобезопасность не нужна. Если же у вас предполагается еще и изменение, то в пул возвращаются указатели на "порченные" объекты, что тоже неправильно.
    Если возможно, конфиг лучше прочитать в начале выполнения, а также паниковать на уровне main.
    В результате и код проще, и тормозить нечему:
    package config
    
    import (
    	"encoding/json"
    	"fmt"
    	"os"
    )
    
    type Cfg struct {
    	// Fields
    }
    
    var (
    	cfg *Cfg
    )
    
    func Config() *Cfg {
    	return cfg
    }
    
    func LoadConfig() error {
    	f, err := os.Open("./config/config.json")
    	if err != nil {
    		return fmt.Errorf("can't open config file: %w", err)
    	}
    	defer f.Close()
    
    	dec := json.NewDecoder(f)
    	var c *Cfg
    	if err := dec.Decode(c); err != nil {
    		return fmt.Errorf("can't decode config file: %w", err)
    	}
    
    	if err := validate(c); err != nil {
    		return fmt.Errorf("can't validate config file: %w", err)
    	}
    	
    	cfg = c
    
    	return nil
    }
    
    func validate(cfg *Cfg) error {
    	// Logic
    	return nil
    }
    Ответ написан
    Комментировать
  • Горутино-безопасное обоащение к sqlite3?

    @falconandy
    Можно ограничить максимальное кол-во соединений до 1:
    db.SetMaxOpenConns(1)
    Это приведет к тому, что и запросы на чтение перестанут выполняться параллельно - так что может подойти, если у вас запросы "шустрые".
    Плюс в том, что в коде не надо будет ничего менять, никаких мьютексов.
    Но так как у вас мест записи в БД немного, то можно использовать и мьютексы - вряд ли вы что-то упустите.
    Если бы мест изменения БД было много, то еще можно рассмотреть вариант обертки над *sql.DB, в которой автоматически использовать мьютекс для всех "подозрительных" методов - например Exec методов (из предположения что в них как правило идет изменение БД) или Query методов, если в запросе есть insert, update или delete.

    Вот еще ссылка по теме: https://stackoverflow.com/questions/35804884/sqlit...
    Ответ написан
    Комментировать
  • Аналог electron только на GO?

    @falconandy
    Гляньте на

    A tiny cross-platform webview library for C/C++/Go... It uses Cocoa/WebKit on macOS, gtk-webkit2 on Linux and Edge on Windows 10.

    A very small library to build modern HTML5 desktop... It uses Chrome browser as a UI layer. Unlike Electron it doesn't bundle Chrome into the app package, but rather reuses the one that is already installed.
    Ответ написан
    Комментировать
  • Как зафиксировать разрыв подключения (НЕ отключения) клиента по HTTP?

    @falconandy
    Посмотрите https://stackoverflow.com/questions/36781707/what-... (ответ, помеченный как лучший). Суть в установке явных таймаутов на чтение/запись на уровне tcp-соединения.
    Ответ написан
    Комментировать
  • Как послать в пул - воркер команду ожидания?

    @falconandy
    Как грубый вариант:

    1. пул воркеров, которые тянут информацию, передавая данные о сессии, но сами (пере)авторизацией не занимаются
    2. отдельная горутина, которая занимается (пере)авторизацией
    3. текущая сессия (токен, куки)
    4. Condition Variable (https://golang.org/pkg/sync/#Cond), с помощью которой синхронизируется доступ у текущей сессии

    Изначально:
    текущей сессии нет, воркеры ждут сигнала от Condition Variable
    Горутина авторизации видит что текущей сессии нет, авторизуется, устанавливает текщую сессию и broadcast-ит событие с помощью Condition Variable. После чего засыпает до сигнала от Condition Variable.
    Воркеры просыпаются и начинают работу.

    Сессия протухла:
    Воркер получает статус необходимости авторизации (например статус 401), сбрасывает текущую сессию (если она установлена и равна той про которую он знал), и broadcast-ит событие с помощью Condition Variable.
    Горутина авторизации просыпается, видит что текущей сессии нет, снова начинает процесс авторизации.
    В это время другие воркеры получают 401, они проверяют, что текущая сессия пуста и засыпают до сигнала от Condition Variable
    Горутина авторизации, закончив процесс авторизации, устанавливает текщую сессию и broadcast-ит событие с помощью Condition Variable. После чего вновь засыпает до сигнала от Condition Variable.
    Приостановленные воркеры просыпаются и переповторяют запросы.
    Воркеры, которые не успели заснуть, просто переповторяют запрос с новым значением сессии.
    Ответ написан
    Комментировать
  • Как в goquery правильно выбрать tr and td?

    @falconandy
    Заработает, если вы обернете в тег table.
    Ответ написан
    2 комментария