Python Array ve Dataframe İşlemleri

21 Oca

Python programlama dilinde dizi halindeki verilerin düzenlenmesi ve işlenmesi sırasında kullanılan numpy ve pandas kütüphaneleridir. Bu kütüphanedeki bazı özellikleri, iki boyutlu örnek Binance mum verileri ile incelenebilir.

import pandas as pd
import numpy as np

data =[
[1704812400000, '46792.27', '49873.00', '42765.00', '46764.01'],
[1704816000000, '46761.41', '49386.00', '23227.11', '46902.88'],
[1704819600000, '46903.83', '47973.00', '23419.63', '46711.45'],
[1704823200000, '46716.00', '48295.00', '10000.01', '46651.90'],
[1704826800000, '46640.50', '48610.00', '10000.01', '46878.98'],
[1704830400000, '46877.27', '48742.96', '10000.01', '46616.88'],
[1704834000000, '46616.50', '49084.00', '10000.01', '45465.18'],
[1704837600000, '45464.24', '48435.00', '23010.01', '46128.00'],
[1704841200000, '46128.00', '48435.00', '19000.00', '46146.32'],
[1704844800000, '46146.32', '48579.00', '10000.01', '45850.47'],
[1704848400000, '45850.47', '47644.00', '22821.01', '45927.79'],
[1704852000000, '45927.74', '47151.00', '12950.01', '45949.93'],
[1704855600000, '45939.45', '47984.00', '16567.21', '46117.10'],
[1704859200000, '46117.04', '48729.00', '10000.01', '45971.96'],
[1704862800000, '45965.99', '46504.00', '44337.00', '45975.73'],
[1704866400000, '45976.00', '46063.59', '10000.01', '45982.48'],
[1704870000000, '45982.48', '46216.51', '10000.01', '45768.47'],
[1704873600000, '45768.47', '46067.35', '45016.00', '45644.22'],
[1704877200000, '45645.89', '46893.14', '44288.00', '45614.43'],
[1704880800000, '45614.43', '45744.30', '45152.33', '45534.09']
]

pandas.Dataframe

Bu diziyi kolon isimleri ile bir dataframe haline getirmek için aşağıdaki komut kullanılır.

# Dataframe from array
df = pd.DataFrame(data, 
        columns=['timestamp', 'open', 'high', 'low', 'close'])

print(df)
             timestamp      open      high       low     close
0  2024-01-09 15:00:00  46792.27  49873.00  42765.00  46764.01
1  2024-01-09 16:00:00  46761.41  49386.00  23227.11  46902.88
2  2024-01-09 17:00:00  46903.83  47973.00  23419.63  46711.45
3  2024-01-09 18:00:00  46716.00  48295.00  10000.01  46651.90
4  2024-01-09 19:00:00  46640.50  48610.00  10000.01  46878.98
5  2024-01-09 20:00:00  46877.27  48742.96  10000.01  46616.88
6  2024-01-09 21:00:00  46616.50  49084.00  10000.01  45465.18
7  2024-01-09 22:00:00  45464.24  48435.00  23010.01  46128.00
8  2024-01-09 23:00:00  46128.00  48435.00  19000.00  46146.32
9  2024-01-10 00:00:00  46146.32  48579.00  10000.01  45850.47
10 2024-01-10 01:00:00  45850.47  47644.00  22821.01  45927.79
11 2024-01-10 02:00:00  45927.74  47151.00  12950.01  45949.93
12 2024-01-10 03:00:00  45939.45  47984.00  16567.21  46117.10
13 2024-01-10 04:00:00  46117.04  48729.00  10000.01  45971.96
14 2024-01-10 05:00:00  45965.99  46504.00  44337.00  45975.73
15 2024-01-10 06:00:00  45976.00  46063.59  10000.01  45982.48
16 2024-01-10 07:00:00  45982.48  46216.51  10000.01  45768.47
17 2024-01-10 08:00:00  45768.47  46067.35  45016.00  45644.22
18 2024-01-10 09:00:00  45645.89  46893.14  44288.00  45614.43
19 2024-01-10 10:00:00  45614.43  45744.30  45152.33  45534.09

Dataframe boyutlarını gösteren shape özelliğidir.

print(df.shape)
(20,5)

Dataframe kolonların tiplerini gösteren dtypes özelliğidir.

print(df.dtypes)
timestamp     datetime64[ns]
open         object
high         object
low          object
close        object
dtype: object

Bir kolonun tipini dönüştürmek için:

# Convert the 'close', 'high' columns from string to float
df["open"] = df["open"].astype(float)
df["high"] = df["high"].astype(float)
df["low"] = df["low"].astype(float)
df["close"] = df["close"].astype(float)
print(df.dtypes)

timestamp    datetime64[ns]
open                float64
high                float64
low                 float64
close               float64
dtype: object

Sayısal tipteki kolonlar üzerinde matematiksel işlemler yapmak mümkündür. String tipteki kolonlarda matematiksel işlemler yapılmak istenirse hata dönecektir.

# divs adında yeni bir kolon açılarak değerler buraya aktarılır.
df["divs"] = df["close"]/df["high"]

# 3'er satırlık hareketli ortalamalar 
df["moving_avg"] = df["close"].rolling(3).mean()

Dataframe de tek bir kolonu, örneğin “close” almak için df[“close”] veya df.close kullanılır.

print(df["close"])
0     46764.01
1     46902.88
2     46711.45
...

Sadece belli kolonlardan yeni bir frame oluşturmak için:

subdf = df[["close", "high"]]
print(subdf)

       close      high
0   46764.01  49873.00
1   46902.88  49386.00
2   46711.45  47973.00
3   46651.90  48295.00
...

Belli özellikteki verilerin temizlenmesi için:

# 'close' içerisinde değeri sıfır olan satırları temizle.
# örneğin tatil günlerinde borsada hacim kolonu sıfır gelebilir.
df[df['close']!=0]

# Bu işlemden sonra index değerinin sıralı olması için index reset gerekir.
df.reset_index(drop=False, inplace=True)

pandas.Dataframe.copy

dataframe copyalam işlemleri için kullanılır.

copydf = df.copy(deep=False) 
# sadece df referansı kopyalanarak yeni bir obje oluşur. 
# df içersinde değişiklik olursa, copydf de değişir.
copydf = df.copy(deep=False)
# yeni bir obje oluşturulur. 
# dolayısıyla df içersinde değişiklik olursa, copydf değişmez.

pandas.Dataframe.to_datetime

Dataframe’in birinci kolonu integer tipinde timestamp olarak geliyor ve okunabilir değildir. Timestamp verilerini okunabilir hale getirmek için aşağıdaki komut kullanılır.

# Convert Integer timestamp
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')

pandas.Dataframe.set_index

Herhangi bir kolon index olarak kullanılmak istenirse, örneğin timestamp kolonu aşağıdaki gibi set_index() fonksiyonu ile düzenlenir.

# set timestamp as index
df.set_index('timestamp', inplace=True)

print(df)
                         open      high       low     close
timestamp                                                  
2024-01-09 15:00:00  46792.27  49873.00  42765.00  46764.01
2024-01-09 16:00:00  46761.41  49386.00  23227.11  46902.88
...

pandas.Dataframe.reset_index

Tekrar sıfırdan başlayan bir index oluşturmak için reset_index() fonksiyonu kullanılır. Şu anda timestamp kolonu index olduğu için bu fonksiyonda drop=True olursa timestamp kolonu reset sırasında silinir.

# new index column: 0,1,2,...
df.reset_index(drop=False, inplace=True)

print(df)
             timestamp      open      high       low     close
0  2024-01-09 15:00:00  46792.27  49873.00  42765.00  46764.01
1  2024-01-09 16:00:00  46761.41  49386.00  23227.11  46902.88
...

pandas.Dataframe.drop

Dataframe’den bir kolonu silmek için drop fonksiyonu kullanılır. örneğin high kolonu silinsin. Fonksiyonda axis=1 parametresi kolon silmek için, axis=0 ise satır silmek için kullanılır.

# drop high column
# df = df.drop(["high"], axis=1)

print(df)
             timestamp      open  low       close
0  2024-01-09 15:00:00  46792.27  42765.00  46764.01
1  2024-01-09 16:00:00  46761.41  23227.11  46902.88
...

Satır silmek için drop fonksiyonuna silinecek satırlar verilir.

# drop row 0
# df = df.drop([0], axis=0)

print(df)
             timestamp      open  low       close
1  2024-01-09 16:00:00  46761.41  23227.11  46902.88
...

pandas.Dataframe.dropna

Eğer veri içerisinde her hangi bir hücrede NaN, None gibi kayıp veriler varsa bunları içeren satırları silmek için dropna() fonksiyonu kullanılır.

# drop row if any cell value is None, NaN, or missing
df = df.dropna()

pandas.Dataframe.head

Dataframe içerisinden ilk N elemanı almak için head() fonksiyonu kullanılır. Bu fonksiyona parametre verilmediğinde default değeri 5’tir.

# get first N items default 5
df = df.head()

print(df)
            timestamp      open      high       low     close
0 2024-01-09 15:00:00  46792.27  49873.00  42765.00  46764.01
1 2024-01-09 16:00:00  46761.41  49386.00  23227.11  46902.88
2 2024-01-09 17:00:00  46903.83  47973.00  23419.63  46711.45

pandas.Dataframe.tail

Dataframe içerisinden son N elemanı almak için tail() fonksiyonu kullanılır. Bu fonksiyona parametre verilmediğinde default değeri 5’tir.

# get last N items default 5
df = df.tail()

print(df)
             timestamp      open      high       low     close
15 2024-01-10 06:00:00  45976.00  46063.59  10000.01  45982.48
16 2024-01-10 07:00:00  45982.48  46216.51  10000.01  45768.47
17 2024-01-10 08:00:00  45768.47  46067.35  45016.00  45644.22
18 2024-01-10 09:00:00  45645.89  46893.14  44288.00  45614.43
19 2024-01-10 10:00:00  45614.43  45744.30  45152.33  45534.09

pandas.Dataframe.take

Belli index verilerini almak için take() fonksiyonu kullanılır

# take items
df = df.take([1,5,7])

print(df)
            timestamp      open      high       low     close
1 2024-01-09 16:00:00  46761.41  49386.00  23227.11  46902.88
5 2024-01-09 20:00:00  46877.27  48742.96  10000.01  46616.88
7 2024-01-09 22:00:00  45464.24  48435.00  23010.01  46128.00

Yeni dizi, vektör oluşturmak

Dataframe boyutunda sıfırlar ile dolu bir vektör oluşturmak:

signals = [0]*len(df)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Unix/Linux Shell ve Shell Script

15 Eki

Kullanıcıların bir bilgisayar organizasyonuna iş yaptırabilmesi için onunla iletişime geçebilmesi gerekir. İşletim sistemi çekirdek yazılımları, son kullanıcıların erişip işlem yapabileceği ortamlar değildir. Bu nedenle kullanıcıların programlar ve komutlar aracılığı ile işletim sistemine ulaşabilmesi ve bilgisayara iş yaptırabilmesi için ara yazılımlar geliştirilmektedir. Bu ara yazılımlar komut satırı veya grafik arabirimi şeklinde olabilmektedir.

Unix veya Linux shell, Linux işletim sistemine erişmek için kullanılan bir kullanıcı arayüzüdür. Kullanıcıların dosya sisteminde gezinmek, dosyaları yönetmek, programları çalıştırmak ve sistemi yapılandırmak gibi görevleri gerçekleştirmek için komutlar yazmasına imkan tanıyan bir programdır.

Linux Ubuntu Shell

Command Prompt olarak adlandırılan $ promptu shell tarafından kullanıcıya sunulur. Shell girilen komutları buradan okur.

Shell Türleri

İki temel shell türü bulunmaktadır.

  • Bourne shell − Eğer Bourne shell kullanılıyorsa, $ karakteri default prompt olarak gelir.
  • C shell − Eğer C shell kullanılıyorsa, % karakteri default prompt olarak gelir.

Bourne shell alt türleri

  • Bourne shell (sh), bulunduğu dizin /bin/sh
  • Korn shell (ksh), bulunduğu dizin /bin/ksh or /bin/ksh93
  • Bourne Again shell (bash), bulunduğu dizin /bin/bash
  • POSIX shell (sh), bulunduğu dizin /bin/ps

C shell alt türleri

  • C shell (csh), bulunduğu dizin /bin/csh
  • TENEX/TOPS C shell (tcsh), bulunduğu dizin /bin/tcsh

Shell Sctipt

Bir shell script temel olarak, yürütme sırasına göre sıralanan komutlar bir listesidir. İyi bir shell scriptte, # işaretinin önünde adımları açıklayan açıklamalar bulunur.

Script içerisinde programlama mantıığında kullanılan koşullu ifadeler, döngüler, dosya işlemleri, değişken tanımlama ve okuma gibi işlemlerin yanısıra fonksiyonlar da tanımlanabilir.

Örnek shell script

Script dosyaları .sh uzantılı olmalıdır. Script’e bir şey eklemeden önce, sistemi bir shell script başlatıldığı konusunda uyarmak gerekir. Bu uyarı aşağıdaki gibi yapılır.

#!/bin/sh

Bu ifade, sisteme aşağıdaki komutların Bourne shell tarafından yürütüleceğini bildirir. Buna shebang denir çünkü # sembolüne hash denir ve ! sembole bang denir.

#!/bin/bash

# Author : Bayram Üçüncü
# Copyright (c) bayramucuncu.com
# Script follows here:
pwd
ls

Bu dosyayı test.sh olarak kaydederek çalıştırılabilir hale getirmek gereklidir.

$ chmod +x test.sh

Çalıştırılabilr test.sh dosyası aşağıdaki şekilde çalıştırılır.

$ ./test.sh

Programın çalıştırılması için ./program_adı kullanılır.

dotnet nuget kullanımı

15 Eki

NuGet, .NET’in paket yöneticisidir. NuGet geliştirici araçları, paket oluşturma ve kullanma desteği sağlar. NuGet Galerisi, tüm paket yazarları ve tüketicileri tarafından kullanılan merkezi bir paket deposudur. Oluşturulanpaketler, güvenli yöntemler ile geleriye gönderilir ve alınır.

Nuget paketi oluşturmadan önce örnek bir dotnet projesi oluşturmak için aşağıdaki komut kullanılabilir.

dotnet new classlib -n DotnetNugetSample

Proje içerisinde de basit bir ILogger interface olabilir.

Bu proje öncelikle bir nuget paketi haline getirilmelidir.

dotnet pack .\DotnetNugetSample\ -o packages
Dotnet package

Oluşturulan bu paketi başka projelerde kullanmak için iki farklı yöntem izlenebilir.

1. local ortamda başka bir projede ilgili packages klasörü bir nuget source olarak eklenir.

dotnet nuget add source D:\nugetsample\packages -n MyNugetPackages

2. sunucuda bir nuget repository üzerine eklenir.

dotnet nuget push D:\nugetsample\packages\DotnetNugetSample.1.0.0.nupkg -s https//api.nuget.org/v3/index.json -k secretkey

Bu işlem ile nuget paketi artık her yerden erişilebilir hale gelir.

Paketi sunucudan silmek için aşağıdaki komut kullanılabilir.

dotnet nuget delete DotnetNugetSample 1.0.0 -s https//api.nuget.org/v3/index.json -k secretkey

Unit Test ve Kodun Varlığının Testi

15 Eki

Aşağıda bulunan controller sınıfının test edileceğini düşünelim.

[ApiController]
[Route("api/[controller]")]
public class TodoItemsController : ApiControllerBase
{
    [HttpGet]
    public async Task<ActionResult<TodoItemBriefDto>> GetTodoItems([FromQuery] Query query)
    {
        return await Mediator.Send(query);
    }
}

Soru: Sınıfa ait her şeyi test etmeli miyim?

1 – TodoItemsController sınıfı ApiControllerAttribute attribute sahiptir.
2 – TodoItemsController sınıfı RouteAttribute attribute sahiptir.
3 – TodoItemsController sınıfı “GetTodoItems” isimli bir meoda sahiptir.
4 – RouteAttribute attribute “api/[controller]” diye bir parametreye sahiptir.
5 – GetTodoItems metodu ActionResult döndürür.
6 – GetTodoItems metodu Query tipinde bir parametre alır.
7 – GetTodoItems metodu TodoItemBriefDto tipinde bir sonuç verir.
8 – GetTodoItems metodu null bir Query parametresine ArgumentNullException fırlatır.
9 – GetTodoItems metodu Query parametresi ile TodoItemBriefDto tipinde bir sonuç döndürür.

Unit test olarak bu testlerin hangileri yazılmalıdır?

Eğer unit test yazıyorsak, bir unit (metod) için belli girdiler ile belli sonuçların döndürdüğünü incelememiz gerekir. Çünkü unit testte kodun varlığı ve işlevselliği test edilir.

O halde yukarıdaki maddelerde 8 ve 9 numaralı maddelerde bir unit(method) test yapılmaktadır.
Diğer maddeler ise kodun var olup olmadığını test etmek için yazılmıştır.

Unit Test metodlarında bulunması gereken özelliklerden burada bahsedilmiştir.

C# Thread ve Task Kullanımı

15 Eki

İşletim sistemleri, verilen görevleri iş parçacıkları ile süreçler halinde yerine getirirler. İşletim sistemindeki bir süreç, temel olarak yürütülmekte olan bir programdır. Program içerisinde yürütülmesi istenen işler bir veya birden fazla thread (iş parçacığı) ile yürütülebilmektedir. Bilgisayar programlamada dilin sağladığı özellikler sayesinde iş parçacıkları asenkron olarak yönetilebilmektedir. Her program bir ana thread ile ayağa kalkıp işi bitene kadar bu thread ile yürütülmektedir. Programı asenkron yönetmek, programın alt süreçlerini, ana thread dışında bir veya birden fazla thread ile yürütmektir.

Özellikle çok çekirdekli işlemcilerden tam performans alabilmek için birden fazla thread ile asenkron işlemler gerçekleştirilebilmektedir. Buna multithreading denilmektedir.

C# Thread ve Task sınıfları

C# programlama dilinde asenkron işlemler için Thread ve Task olmak üzere iki sınıf tanımlanmıştır. (Linkler .Net 7.0 versiyonu doküman sayfasına aittir.)

Thread Sınıfı

Thread sınıfı bir iş parçacığı oluşturup denetler, çalışma önceliğini ayarlar ve durumunu bildirir. Geriye bir değer döndürmeyen, asenkron çalışan tek bir işlemi temsil eder. C# ortamında çalışan bir thread hakkında bazı temel bilgileri elde etmek mümkündür.

// Thread Id bilgisi
Thread.CurrentThread.ManagedThreadId

// Thread durum bilgisi
Thread.CurrentThread.ThreadState
 
// Background olup olmadığı bilgisi
Thread.CurrentThread.IsBackground

//ThreadPool'dan alınıp alınmadığı bilgisi
Thread.CurrentThread.IsThreadPoolThread

Thread nesnesi oluşuturma örneği;

// Run with new Thread
var thread = new Thread(()=>Write("*"));
thread.Start();

// Run with Main Thread 
Write("-");

void Write(string input)
{
    for (var i = 0; i < 10; i++)
        Console.Write(input);
}

// Output
--**----********----

Aynı Write metodu hem main thread hemde thread nesnesi tarafından çalıştırılmaktadır. Output incelendiğinde biraz “*” karakteri biraz “-” karakterinin ekrana yazıldığı görülmektedir.

C# dilinde yönetilen (managed) thread,ya arka planda (background) ya da ön planda (foreground) çalışır. Thread’in bu özelliğini öğrenmek için Thread.IsBackground property kullanılır.

Foreground Thread

Foreground thread, main thread’in işini bitirip sonlanmasından etkilenmez. Kendi işi bittiğinde sonlanır. Bu, C#’ta ön plandaki bir iş parçacığının ömrünün ana iş parçacığına bağlı olmadığı anlamına gelir. Thread’ler default olarak foreground özelliğinde oluşturulurlar.

var thread = new Thread(()=>Write("*"));
thread.Start();

Console.WriteLine("Main thread finished");

void Write(string input)
{
    for (var i = 0; i < 10; i++)
    {
        Thread.Sleep(100);
        Console.Write(input);
    }
}


// Output
Main thread finished
**********

thread.Start() metodu çalıştırıldıktan sonra main thread Console.WriteLine(“Main thread finished”); metodunu çağırır ve main program sonlanır. Ancak thread nesnesi, foreground özelliğinde olduğu için işini bitirene kadar çalışmaya devam eder.

Background Thread

Background thread’lerin çalışması main thread veya diğer tüm foreground thread’lerin çalışır olması durumda olmasına bağlıdır.

var thread1 = new Thread(()=>Write("*"));
thread1.IsBackground = true;
thread1.Start();

Console.WriteLine("Main thread finished");

void Write(string input)
{
    for (var i = 0; i < 10; i++)
    {
        Thread.Sleep(100);
        Console.Write(input);
    }
}


// Output
Main thread finished

Burada main thread Console.WriteLine(“Main thread finished”); metodunu çağırıp hemen sonlandığı için background thread de işini yapamadan yani ekrana birşey yazamadan sonlanmıştır. Eğer bir foreground thread2 tanımlanıp çalıştırılsaydı, o bitene kadar thread1 işini yapacaktı.

Task Sınıfı

Task sınıfı asenkron bir operasyonu temsil eder. Task-based asyncronious pattern kavramının tamel yapı taşıdır. İşlem sonucunda geriye bir değer döndürebilme özelliğine sahiptir.

Lambda ifadesi ile task nesnesi oluşturma;

Task t1 = new Task(
    () => Console.WriteLine("Working"));
t1.Start();
// t1'nin çalıştığını göstermek için main thread bloke edilsin.
t1.Wait();

Parametre alan Lambda ifadesi ile task nesnesi oluşturma;

Task t1 = new Task(
    param=> Console.WriteLine($"Working param: {param}"), 2);
t1.Start();
// t1'nin çalıştığını göstermek için main thread bloke edilsin.
t1.Wait();

Action metod task nesnesi oluşturma;

var action = (object? param) =>{
    Console.WriteLine($"I am working with param: {param}");
};

Task t1 = new Task(action, 2);
t1.Start();
// t1'nin çalıştığını göstermek için main thread bloke edilsin.
t1.Wait();

Task nesneleri arka plan (background) thread olarak hizmet vermektedir. Bu nedenle main thread sonlanmadan çalışmasını görebilmek için t1.Wait(); kullanılmıştır.

var action = (object? param) =>{
    Console.WriteLine(Thread.CurrentThread.IsBackground);
    Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    Console.WriteLine($"I am working with param: {param}");
};

Task t1 = new Task(action, 2);
t1.Start();
t1.Wait();

Task nesnelerinin kullandıkları thread, ThreadPool’a aittir. Bunu Thread.CurrentThread.IsThreadPoolThread property ile anlayabiliriz.

ThreadPool Nedir? ThreadPool Neden Kullanılır?

ThreadPool tipi, uygulamada görevleri yürütmek, asenkron I/O süreçlerini işletmek, timer’ları işletmek gibi işlemler için bir thread havuzu sunar. Task objeleri, bu havuz içerisinden bir thread alarak işlemlerini yürütürler. Bu sayede thread oluşturma, oluşturulan thread için resource ayırma, görevi yürütme ve Garbage Colleciton ile kaynakların serbest bırakılması adımları tekrar tekrar işletilmez. ThreadPool’da arka planda bir dizi görevi gerçekleştirmek için yeniden kullanılabilecek bir thread havuzundan yeniden kullanılabilir thread’lerden bir tane alınarak işlemeler gerçekleştirilir ve thread havuza geri bırakılır.

ThreadPool üzerindeki aktif thread sayısını şu şekilde öğrenmek mümkündür;

Console.WriteLine(ThreadPool.ThreadCount);

ThreadPool üzerinde tanımlanabilecek maksimum worker thread sayısı ve maksimum I/O işlemleri için kullanılabilecek thread sayısını şu şekilde öğrenilebilir;

ThreadPool.GetMaxThreads(out var worker, out var ioCompletion);
Console.WriteLine("{0} / {1}", worker, ioCompletion);

Task içerisinde çalışan thread, ThreadPool içerisinden alınır.

Task Oluşturma ve Yürütme

Bir taskı oluşturmak ve yürütmek için birden fazla yöntem vardır. En yaygın kullanılanı ise Task.Run() metodudur. Bu yöntemde Task default parametreleri ile oluşturulur ve kullanılır.

 Task.Run(() =>
 {
     Console.WriteLine("Working");
     Console.WriteLine(Thread.CurrentThread.IsBackground);
     Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
 });

Bir diğer yöntem ise Task.Factory.StartNew() statik metodunun çalıştırılmasıdır. Bu yöntemde StartNew() metodunun overload edilmiş tipleri ile Task’a parametre geçilebilmektedir.

 Task.Factory.StartNew(() =>
 {
     Console.WriteLine("Working");
     Console.WriteLine(Thread.CurrentThread.IsBackground);
     Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
 });

Merhaba Linux Ubuntu Desktop

9 Eki

İş dünyasındaki sunucu ortamlarda sürekli haşır neşir olduğum linux işletim sistemi, son yıllarda container ortamların iyice yaygınlaşmasıyla birlikte yol arkadaşım oldu.

Kişisel bilgisayarımda Linux işletim sistemine taşınmak, uzun süredir aklımda olan planlardan biriydi. Bunun en önemli nedeni, bilgisayrımda yaşadığım kaynak yetersizliğiydi. Bu yetersizliğin en önemli nedenlerinden biri de Windows işletim sistemi üzerinde Linux tabanlı araçlarının kurulabilmesi için yüklenen sanallaştırma platformlarıydı. Bir süre sonra windows üzerinde terminali bile linux tabanlı kullanmaya başlamıştım. O halde uzun süredir kullandığım Windows işletim sisteminden Linux ortamında bir desktop dağıtıma geçme vaktinin geldiğine karar verdim. Community desteğinin de geniş olması nedeniyle seçimim Ubuntu desktop oldu.

Linux dünyasına geçmeden önce geliştirme araçlarımın linux desteğini inceledim ve artık geçişi başlatmaya karar verdim. Refus programı ile bir USB kurlum olşuturdum ve yedekteki SSD diskim üzerine kurulumu yaptım.

Windows çok kullanışlı ve alışık olduğum bir işletim sistemi olması nedeniyle, Linux desktopa alışamam bir hafta kadar sürdü. Kurulumlar, dosya sistemi, sürücülerin tanıtılması vs. derken bir hafta sonunda acemiliğimi atmış oldum. Server versiyondan alışık olduğum için bir çok kurulumu terminal ile yapmaya çalıştım.

Performans konusunda gayet memnun kaldım. Windows üzerinde container ortamlarda ayağa kaldırdığım araçları Linux üzerinde kaldırdığımda kaynak kullanımı neredeyse %50 civarında fark ettiğini gördüm. Bilgisayarın rahatlamasıyla bende rahat bir nefes almış oldum.

Sonuç olarak, eğer geliştirme değil de ofis veya ev amaçlı bir desktop işletim sistemi seçecek olursam yine windows tercih ederdim. Ancak yazılım ve mühendislik amaçlı kullanımda Unix tabanlı bir işletim sistemini (Linux veya Mac) tercih ederim.

Python ile Proxy Http Request

27 Eyl

Python programlama dilinde http isteği en temel hali ile aşağıdaki gibi yapılabilmektedir. Bu işlem için requests modülünün import edilmesi gerekmektedir.

import requests

url = 'https://my-web-api.com'

response = requests.get(url)

print(response.text)

Bu isteği bir proxy aracılığı ile yapmak için aşağıdaki gibi düzenlemek gerekmektedir.

import requests

url = 'https://my-web-api.com'

proxies = {
   'http': 'http://proxy.example.com:8080',
   'https': 'http://secureproxy.example.com:8090',
}

response = requests.get(url, proxies=proxies)

print(response.text)

En Sık Kullanılan Git Komutları

24 Eyl

Developerlar için faydalı olabilecek Git komutları aşağıda liste halinde sunulmuştur.

git branch   
# Branch listele
git branch <new-branch-name>   
# Yeni brach oluştur
git checkout <other-branch>   
# Branch’e geç
git checkout -b <new-branch>   
# Branch oluştur ve ona geç
git branch -d <delet-branch-name>  
# Branch sil
git log  -- oneline 
# Commit history, tek satırda
git status 
# Stageing Directory'ye atılan ve atılmayanları göster
git add <file> 
# Working Directory'deki <file> Staging Directory'ye at
git add <dircetory> 
# Working Directory'deki <directory> Staging Directory'ye at
git add . 
# Working Directory'deki herşeyi Staging Directory'ye at
git reset . 
# Staging Directory'deki herşeyi Working Directory'ye at
git commit -m 
# "Commit" mesajı ile commit et
git revert <commit id> 
# Yapılan Commit geri al
git push -u <remote> <branch-name>  
# Local ortamda yapılan Commit'leri uzal sunucuya gönder 
git config --global core.autocrlf true
# Unix temelli OS'de kullanılan satır sonu karakteri kullan  

          

Javascript import ve requeire farkı

6 Oca

Javascript dilinde import ve require anahtar kelimeleri, modülleri kod içerisine aktarmak için kullanılır. Modülleri yüklerken NodeJS tarafında require kullanılırken, Ecmascript 6 tarafında import kullanılır.

NodeJS de kullanılan require, modülleri senkron bir şekilde yükler. Yani modül yüklenene kadar kod bloke olur ve yükleme işleminden sonra kullanılabilir. Ecma script ile kullanılan import ise modülü asenkron olarak yükler ve kod yükleme sırasında bloke olmaz.

require ve import arasındaki temel fark, require sadece modül içeri aktarma işlemi sırasında kullanılırken, import hem tüm modülün içeri aktarımı, hem de ihtiyaç halinde bir modül içerisinden tek başına export edilmiş türlerin aktarımı için kullanılır. Tek başına export edilen türler birer fonksiyon, sabit, nesne olabilir.

require ile modül yükleme

Örneğin math modülünü require ile yüklemek için aşağıdaki komut kullanılır.

const math = require('math');

math modülüne ait tekil bir export edilmiş tipi yüklemek için:

const log = require('math').log;

import ile modül yükleme

Örneğin math modülünün tümünü import ile yüklemek için aşağıdaki komut kullanılır.

import * as math from 'math';

math modülüne ait tekil bir export edilmiş tipi yüklemek için:

import {log} from 'math';

math modülüne ait tekil olarak birden fazla export edilmiş tipi yüklemek için:

import {log, factorial} from 'math';

import()

Math modülünün tanımlanması:

// math.js
export const pi = 3.14;
export const e = 2.71828;

Math modülünün calculate modülüne yüklenmesi.

// calculate.js
import { pi, e } from './math';
console.log(pi); // output 3.14
console.log(e); // output 2.71828

Mikroservis Repository Yapılandırması

6 Oca

Mikroservis yaklaşımında, kod depolama için iki seçenek bulunur. Birincisi tüm servislerin tek bir repository içerisinde tutulması. İkincisi her bir servis için ayrı repository oluşturulması.

Tek bir repository kullanımı

Genel olarak, tüm mikro servislerde tek bir repository tercih edilebilir, ancak kod büyüdükçe her bir servis için bir alt klasör dizini ve proje yapısını yönetmek zor olabilir. Tüm mikroservisleri tek bir havuza koymaya karar vermeden önce dikkate alınması gereken şeyler şunlardır:

Developer Sınırlarının Belirlenmesi

Tüm mikroservislerin kodu tek bir havuzda olduğundan, aralarında gerçek bir fiziksel sınır yoktur. Bu nedenle geliştiriciler, projeler arasında bir referans veya benzeri eklemeler yaparak diğer mikroservislerdeki bazı kodları kullanabilirler. Tüm mikroservislerin tek bir havuzda olması, geliştiricilerin sınırları aşmaması ve bunları yanlış kullanmaması için biraz disiplin ve kurallar konulması gerektirecektir. Kod sınırları belirlenmediğinde, developer sınırları belirlemek durumunda kalınabilir.

Paylaşılan Kod Oluşumu

Kod altyapısında servislerde ortak kullanılabilecek kodların cazibesine kapılarak, paylaşılan kodlar kümesi oluşabilir. Birbirinden bağımsız servisler oluşturmak amacıyla çıkılan mikroservis yolunda bağımlılıklar oluşmaya başlayabilir. Normalde ortak kullanılan kodlar paketlenerek Nuget, Npm gibi depolara aktarılarak kullanmak uygundur. Doğrudan kod repository içerisinde bağımlılık oluşturmak, servislerin bağımsız geleceği açısından uygun değildir.

Git Yönetimi

Çok fazla ekip üyesinin bir repository üzerinde çalışması pull request ve branch yönetimi açısından zordur. Sürekli gelen commit talepleri ve merge ile çakışmalar artabilir. Bir ekibi ilgilendirmeyen değişikliklerin bildirim mesajları, mailleri o ekibe de düşmeye başlar.

CI/CD Süreçleri

Kodu oluşturmak, test etmek ve/veya dağıtmak için Azure DevOps, Jenkins gibi araçlar kullanıldığında, Jenkins ve GitHub arasındaki entegrasyon gibi bazı yapılandırma güçlükleriyle karşılaşabilirsiniz. Birisi herhangi birmikroservise karşı bir merge/pull request isteği oluşturursa, yalnızca kodun belirli bir bölümünü (ilgili mikroservisi) oluşturacak/test edecek bir ardışık düzen yapılandırmak gerekir. Buna uygun bir yöntem de bulmak gerekecek. Kodda ilgili klasörde veya tag işleminde bir değişiklik olduğunda ilgili build adımının çalışması ve bir docker imaj çıkarması gibi senaryolar oluşturmak gerekebilir. Aynı senaryolar deployment adımları için de geçerlidir.

Sonuç

Bu sorunların tümü veya çoğu, bazı ekstra yönetim ve yapılandırma ile çözülebilir, ancak yine de ne kadar ek çabayla karşılaşabileceğinizi iyi tasarlamak gerekir. Bu nedenle genel tavsiye, mümkünse her bir mikroservis için ayrı repository kullanmak olacaktır.