Показувати повідомленя

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Показувати повідомленя

Messages - Tuvze

#1
У Python concurrency (паралелізм) може значно підвищити продуктивність в I/O-інтенсивних або CPU-інтенсивних завданнях. Однак через обмеження GIL (Global Interpreter Lock) у Python важливо вибрати правильний підхід. У цій статті ми порівняємо підходи threading, multiprocessing та asyncio і покажемо сценарії, де кожен з них є найбільш підходящим, з реальним прикладом застосування.

1. Threading (Потоки)
  • Підходить для I/O-bound завдань (мережеві запити, читання/запис файлів).
  • Через GIL не забезпечує справжній паралелізм у CPU-bound завданнях.
  • Легкі та швидко запускаються.

Основний приклад:
import threading
import time

def dosya_indir(url):
    print(f"Шу url завантажується...")
    time.sleep(2)  # Симуляція мережевого запиту
    print(f"Шу url завершено.")

urls = ["site1.com", "site2.com", "site3.com", "site4.com"]
threads = []
for url in urls:
    t = threading.Thread(target=dosya_indir, args=(url,))
    threads.append(t)
    t.start()
for t in threads:
    t.join()
print("Усі завантаження завершено.")

2. Multiprocessing (Багатопроцесність)
  • Забезпечує справжній паралелізм для CPU-bound завдань (GIL не впливає).
  • Кожен процес використовує окремий простір пам'яті → більше споживання пам'яті.
  • Для обміну даними потрібні структури, такі як Queue, Pipe, Manager.

Приклад CPU-інтенсивного завдання:
from multiprocessing import Process, cpu_count
import time

def hesapla(n):
    toplam = 0
    for i in range(n):
        toplam += i ** 2
    print(f" {n} для результату: {toplam}")

if __name__ == "__main__":
    sayilar = [10_000_000] * cpu_count()
    processes = []
    for sayi in sayilar:
        p = Process(target=hesapla, args=(sayi,))
        processes.append(p)
        p.start()
    for p in processes:
        p.join()
    print("Усі обчислення завершено.")

3. Asyncio (Асинхронне програмування)
  • Сучасний і найпотужніший підхід (особливо в Python 3.7+).
  • Керує тисячами паралельних завдань в одному потоці.
  • Найефективніший метод для I/O-bound завдань (мережа, бази даних, виклики API).

Реалістичний приклад asyncio: Паралельне отримання даних з кількох API.
import asyncio
import aiohttp
import time

async def api_cagir(session, url):
    async with session.get(url) as response:
        data = await response.json()
        print(f"{url} -> {len(data)} елементів отримано")
        return data

async def ana():
    urls = [
        "https://jsonplaceholder.typicode.com/posts",
        "https://jsonplaceholder.typicode.com/comments",
        "https://jsonplaceholder.typicode.com/albums",
        "https://jsonplaceholder.typicode.com/photos"
    ]
    async with aiohttp.ClientSession() as session:
        gorevler = [api_cagir(session, url) for url in urls]
        sonuclar = await asyncio.gather(*gorevler)
        print(f"Всього {sum(len(s) for s in sonuclar)} елементів зібрано")

if __name__ == "__main__":
    basla = time.time()
    asyncio.run(ana())
    print(f"Загальний час: {time.time() - basla:.2f} секунд")

Який підхід використовувати коли? (Порівняння)
  • Найкраще використання: Для threading - I/O-bound; для multiprocessing - CPU-bound; для asyncio - I/O-bound (високий обсяг).
  • Справжній паралелізм: Для threading - Ні (GIL); для multiprocessing - Так; для asyncio - Ні (один потік).
  • Споживання пам'яті: Для threading - Низьке; для multiprocessing - Високе; для asyncio - Дуже низьке.
  • Вартість запуску: Для threading - Низька; для multiprocessing - Висока; для asyncio - Дуже низька.
  • Складність коду: Для threading - Середня; для multiprocessing - Висока; для asyncio - Середня-Висока.
  • Найпопулярніші бібліотеки: Для threading - requests + ThreadPoolExecutor; для multiprocessing - concurrent.futures; для asyncio - aiohttp, httpx, aiomysql.

Практичні рекомендації
  • Для невеликих-середніх I/O-завдань → asyncio (стандарт майбутнього).
  • Для важкої математики/обчислень → multiprocessing або concurrent.futures.ProcessPoolExecutor.
  • Для простих скриптів і швидких рішень → threading + ThreadPoolExecutor.

У нашому форумі ви можете поділитися своїми проектами concurrency, обговорити, який метод найкраще підходить для вашого сценарію використання.
#2
Вступ
У 2026 році додатки, орієнтовані на дані, вже не можуть бути пакетними, вони мусять працювати в реальному часі. У цьому посібнику ми створимо з нуля Панель приладів для відстеження цін на криптовалюти в реальному часі:
  • FastAPI backend: Трансляція цін у реальному часі через WebSocket
  • Redis Pub/Sub: Керування потоком даних
  • Streamlit frontend: Інтерактивна панель приладів, що оновлюється миттєво
  • Plotly для професійних графіків
  • Pandas для швидкої обробки даних
  • Симульоване джерело даних (у реальності можна використовувати API Binance, CoinGecko)

Проект пропонує production-ready основу: масштабовану, чисту та сучасну.

Вимоги
Python 3.11+, Redis (легко з docker: docker run -p 6379:6379 redis)
pip install fastapi uvicorn redis websockets streamlit pandas plotly httpx py
1. Структура проекту
Цитувати(Тут оригінал не має детального опису структури, але зображення показує дерево файлів:
real-time-crypto-dashboard/
├── backend/
│  ├── main.py  # FastAPI app
│  ├── ws_manager.py  # WebSocket connection manager
│  ├── price_simulator.py
├── frontend/
│  ├── dashboard.py  # Streamlit app
└── requirements.txt
)

2. Backend: FastAPI + WebSockets + Redis
backend/ws_manager.py
from fastapi import WebSocket
from typing import List
import asyncio
import json

class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)

backend/price_simulator.py (симуляція замість реального API – якщо бажаєте, переведіть на WebSocket Binance)
import asyncio
import random
import json
from datetime import datetime

async def simulate_price_stream(manager: ConnectionManager, redis_client):
    symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT"]
    while True:
        for symbol in symbols:
            price = round(
                random.uniform(20000, 100000) if symbol == "BTCUSDT" else
                random.uniform(1000, 5000) if symbol == "ETHUSDT" else
                random.uniform(50, 300), 2
            )
            data = {
                "symbol": symbol,
                "price": price,
                "timestamp": datetime.utcnow().isoformat()
            }
            # Публікувати в Redis (інші сервіси можуть прослуховувати)
            await redis_client.publish("crypto_prices", json.dumps(data))
            # Пряма трансляція через WebSocket
            await manager.broadcast(json.dumps(data))
        await asyncio.sleep(1)  # Оновлення кожну 1 секунду

backend/main.py
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
import asyncio
import redis.asyncio as redis
from ws_manager import ConnectionManager
from price_simulator import simulate_price_stream
import os
from dotenv import load_dotenv

load_dotenv()

app = FastAPI()
manager = ConnectionManager()
redis_client = redis.from_url("redis://localhost:6379/0")

@app.on_event("startup")
async def startup_event():
    asyncio.create_task(simulate_price_stream(manager, redis_client))

@app.websocket("/ws/prices")
async def websocket_endpoint(websocket: WebSocket):
    await manager.connect(websocket)
    try:
        while True:
            await websocket.receive_text()  # Ми не хочемо повідомлень від клієнта, але
    except WebSocketDisconnect:
        manager.disconnect(websocket)

@app.get("/")
async def root():
    return {"message": "Backend панелі приладів криптовалют в реальному часі працює"}

3. Frontend: Streamlit Dashboard
frontend/dashboard.py
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import asyncio
import json
import websockets
from datetime import datetime
import threading

st.set_page_config(page_title="Панель приладів криптовалют в реальному часі 2026", layout="wide")

# Зберігання даних
if "price_data" not in st.session_state:
    st.session_state.price_data = {sym: pd.DataFrame(columns=["timestamp", "price"]) for sym in ["BTCUSDT", "ETHUSDT", "SOLUSDT"]}

async def listen_websocket():
    uri = "ws://localhost:8000/ws/prices"
    async with websockets.connect(uri) as websocket:
        while True:
            try:
                message = await websocket.recv()
                data = json.loads(message)
                symbol = data["symbol"]
                price = data["price"]
                ts = pd.to_datetime(data["timestamp"])
                new_row = pd.DataFrame({"timestamp": [ts], "price": [price]})
                st.session_state.price_data[symbol] = pd.concat([st.session_state.price_data[symbol], new_row], ignore_index=True).tail(300)  # Зберігати останні 300 записів
                # Тригер перезапуску Streamlit (не thread-safe, але для простої демо)
                st.rerun()
            except Exception as e:
                print(f"Помилка WebSocket: {e}")
                await asyncio.sleep(5)

# Запуск прослуховувача WebSocket у фоновому потоці
if "ws_thread" not in st.session_state:
    st.session_state.ws_thread = threading.Thread(
        target=lambda: asyncio.run(listen_websocket()), daemon=True
    )
    st.session_state.ws_thread.start()

st.title("Панель приладів криптовалют в реальному часі (2026)")

col1, col2 = st.columns(2)

for symbol in st.session_state.price_data:
    df = st.session_state.price_data[symbol]
    if not df.empty:
        with (col1 if symbol == "BTCUSDT" else col2):
            st.subheader(f"{symbol} - Остання ціна: ${df['price'].iloc[-1]:,.2f}")
            fig = go.Figure()
            fig.add_trace(go.Scatter(
                x=df["timestamp"],
                y=df["price"],
                mode='lines+markers',
                name=symbol,
                line=dict(color='royalblue' if symbol == "BTCUSDT" else 'orange')
            ))
            fig.update_layout(
                title=f"{symbol} Останні 5 хвилин",
                xaxis_title="Час",
                yaxis_title="Ціна (USDT)",
                height=400,
                template="plotly_dark" if st.get_option("theme.base") == "dark" else "plotly"
            )
            st.plotly_chart(fig, use_container_width=True)

st.markdown("---")
st.caption("Backend: FastAPI + WebSockets + Redis | Frontend: Streamlit | Версія: 1.0.0")

4. Запуск
Термінал 1: Запустіть Redis (з docker)
Термінал 2:
cd backend
uvicorn main:app --reload --port 8000

Термінал 3:
cd frontend
streamlit run dashboard.py

5. Поради для просунутих (2026)
• Реальні дані: Інтегруйте WebSocket з ccxt або binance-python
• Замість Redis: Масштабуйте з Kafka / RabbitMQ
• Замість Streamlit: Taipy або Solara (більш професійний UI)
• Docker Compose: Підніміть весь стек однією командою
• Аутентифікація: JWT + FastAPI Users
• Деплой: Render / Railway / Fly.io (є безкоштовні рівні)
#3
У 2025 році в Туреччині ніхто більше не створює зведені таблиці в Excel. Pandas + Plotly стали стандартом.

У цьому посібнику ми попрактикуємося з реальними даними про продажі (дані про електронну комерцію в Туреччині за 2020–2025 роки):
  • Очищення та аналіз даних за допомогою Pandas 2.2
  • Інтерактивні графіки за допомогою Plotly
  • Створення живого дашборду за 5 хвилин за допомогою Streamlit
  • Безкоштовне розгортання на Railway / Streamlit Cloud
  • Сумісність з мобільними пристроями + темний режим

1. Встановлення (найактуальніші пакети 2025 року)

python -m venv veri-dashboard
cd veri-dashboard
Scripts\activate
pip install pandas==2.2.2 plotly==5.22 streamlit==1.38 openpyxl python-dotenv

2. Приклад даних (satislar_2025.xlsx)
Приклад таблиці Excel:

[th]Дата[/th]
[th]Продукт[/th]
[th]Категорія[/th]
[th]Кількість[/th]
[th]Ціна[/th]
[th]Місто[/th]
[th]Оплата[/th]
2025-01-15iPhone 16Електроніка245000СтамбулКредит
2025-01-16СветрОдяг5850АнкараГотівка
.....................

3. Аналіз даних – analysis.py
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
import locale

# Встановлення локалі для Туреччини 2025
locale.setlocale(locale.LC_TIME, 'tr_TR.UTF-8')

# Завантаження даних
df = pd.read_excel("satislar_2025.xlsx", parse_dates=["Tarih"])

# Очищення
df["Toplam"] = df["Adet"] * df["Fiyat"]
df["Ay"] = df["Tarih"].dt.strftime("%Y-%m")
df["Gün"] = df["Tarih"].dt.day_name(locale='tr_TR')

print("Загальний дохід:", f"₺{df['Toplam'].sum():,}")
print("Найпопулярніша категорія:", df.groupby("Kategori")["Adet"].sum().idxmax())

4. Інтерактивний дашборд – app.py (Streamlit)
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from pathlib import Path

st.set_page_config(page_title="Дашборд продажів 2025", layout="wide", page_icon="📊")

# Темний режим
st.markdown("""
<style>
.css-1d391kg {padding-top: 1rem; padding-bottom: 3rem;}
.css-18e3th9 {padding-top: 1rem;}
</style>
""", unsafe_allow_html=True)

@st.cache_data
def load_data():
    df = pd.read_excel("satislar_2025.xlsx", parse_dates=["Tarih"])
    df["Toplam"] = df["Adet"] * df["Fiyat"]
    df["Ay"] = df["Tarih"].dt.strftime("%Y-%m")
    df["Ay Adı"] = df["Tarih"].dt.strftime("%B %Y")
    return df

df = load_data()

st.title("Дашборд продажів електронної комерції в Туреччині - 2025")
st.markdown("---")

# KPI
col1, col2, col3, col4 = st.columns(4)
total_revenue = df["Toplam"].sum()
total_orders = len(df)
avg_basket = total_revenue / total_orders if total_orders > 0 else 0
top_city = df["Şehir"].value_counts().index[0]

col1.metric("Загальний оборот", f"₺{total_revenue:,.0f}")
col2.metric("Загальна кількість замовлень", f"{total_orders:,}")
col3.metric("Середній чек", f"₺{avg_basket:,.0f}")
col4.metric("Найпопулярніше місто", top_city)

st.markdown("---")

# Тренд продажів за місяцями
col1, col2 = st.columns(2)
with col1:
    monthly = df.groupby("Ay")["Toplam"].sum().reset_index()
    template = "plotly_dark" if st.checkbox("Темний режим", True) else "plotly"
    fig = px.line(monthly, x="Ay", y="Toplam", title="Тренд обороту за місяцями", markers=True, template=template)
    fig.update_yaxes(title="Оборот (TL)", tickprefix="₺")
    st.plotly_chart(fig, use_container_width=True)

with col2:
    category = df.groupby("Kategori")["Toplam"].sum().reset_index()
    fig2 = px.pie(category, values="Toplam", names="Kategori", title="Розподіл продажів за категоріями")
    st.plotly_chart(fig2, use_container_width=True)

# Продажі за містами
st.subheader("Продажі за містами")
city_sales = df.groupby("Şehir")["Toplam"].sum().reset_index()
fig3 = px.bar(city_sales.sort_values("Toplam", ascending=False).head(10), x="Şehir", y="Toplam", title="Топ-10 міст за продажами")
st.plotly_chart(fig3, use_container_width=True)

# Таблиця + фільтри
st.subheader("Детальна таблиця продажів")
kategori_sec = st.multiselect("Оберіть категорію", df["Kategori"].unique(), default=df["Kategori"].unique())
sehir_sec = st.multiselect("Оберіть місто", df["Şehir"].unique(), default=df["Şehir"].unique())
filtered = df[df["Kategori"].isin(kategori_sec) & df["Şehir"].isin(sehir_sec)]
st.dataframe(filtered, use_container_width=True)

# Експорт в Excel
csv = filtered.to_csv(index=False).encode('utf-8')
st.download_button("Завантажити Excel", csv, "satislar_filtreli.csv", "text/csv")

5. Запуск


streamlit run app.py
# http://localhost:8501


6. Безкоштовне розгортання (2 варіанти)
Варіант 1: Streamlit Cloud (30 секунд)

git init
git add .
git commit -m "first"
# streamlit.io → New app → Підключіть репозиторій GitHub → Deploy
# https://satis-dashboard-2025.streamlit.app


Варіант 2: Railway.app

railway login
railway init
railway up
# Автоматичне розгортання

7. Продуктивність (2025)

[th]Інструмент[/th]
[th]Час розгортання[/th]
[th]Сумісність з мобільними[/th]
[th]Інтерактивність[/th]
[th]Вартість[/th]
Power BI10+ хвилинСередняСередня$10/міс
Tableau15+ хвилинГарнаГарна$70/міс
Streamlit + Plotly30 секундВідміннаВідміннаБезкоштовно

Висновок
Цей дашборд пропонує:
  • Фільтрацію в реальному часі
  • Сумісність з мобільними та десктопними пристроями
  • Експорт в Excel
  • Темний режим
  • Живий за 5 хвилин
  • Готовий для презентації керівництву!

Повний вихідний код (працюючий):
https://github.com/kullanicin/veri-dashboard-2025

Жива демонстрація:
https://satis-dashboard-2025.streamlit.app